Commit 398aff6b authored by qiujianhui's avatar qiujianhui

create haptic demo and README.md

parent a6412477
*.iml
.gradle
/local.properties
/.idea/caches
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
.DS_Store
/build
/captures
.externalNativeBuild
.cxx
local.properties
# Default ignored files
/shelf/
/workspace.xml
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<bytecodeTargetLevel target="11" />
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="testRunner" value="GRADLE" />
<option name="distributionType" value="DEFAULT_WRAPPED" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleJvm" value="Android Studio default JDK" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" />
</set>
</option>
</GradleProjectSettings>
</option>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ASMIdeaPluginConfiguration">
<asm skipDebug="false" skipFrames="false" skipCode="false" expandFrames="false" />
<groovy codeStyle="LEGACY" />
</component>
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>
\ No newline at end of file
HapticDemo
\ No newline at end of file
# 一、概述
HapticPlayer是一套振动波形的生成框架,可以通过参数或者HE格式为你的线性马达机器定制出丰富的振动效果。
# 二、支持设备
Xiaomi-高压线性马达设备
如小米9 pro 5G,小米10全系列(小米10、小米10pro等),小米11全系列(小米11、小米11pro等),小米12全系列(小米12、小米12s、小米12s ultra等),小米mix4,小米mix fold,红米K系列(红米K30S至尊纪念版、K40全系列、K50全系列),红米Note系列(红米Note10 pro、红米Note11全系列)
# 三、API接口
#### android.os.DynamicEffect
| 接口 | 说明 |
| --------------------------------- | ------------------------------------------------------------ |
| DynamicEffect create(String json) | 系统实现一种扩展的振动效果android.os.DynamicEffect。其中create为静态方法,参数为振动效果描述的json字符串,用来创建DynamicEffect。 |
#### android.os.HapticPlayer
HapticPlayer为振动接口的封装(注:带\*的接口系统侧可能会不支持,调用后系统侧不会进行处理)
| 接口 | 说明 |
| ------------------------------------------------------------ | ------------------------------------------------------------ |
| HapticPlayer (DynamicEffect effect) | 构造方法,effect为创建的振动效果DynamicEffect |
| boolean isAvailable() | 判断系统是否支持 |
| void start(int loop) | 开始播放效果@param: loop 循环次数, 1不循环,大于1循环次数,-1无限循环; |
| void start(int loop, int interval, int amplitude) | 开始播放效果@param loop 循环次数, 1不循环,大于1循环次数,-1无限循环;@param interval 循环间隔, 0-1000, 每次震动循环播放的间隔,单位ms;@param amplitude 振动强度,1-255,1最小,255最大。此参数用于修饰HE文件,进行整体的强度信号调整/缩减; |
| void start(int loop, int interval, int amplitude, int freq) | 开始播放效果@param loop 循环次数, 1不循环,大于1循环次数,-1无限循环;@param interval 循环间隔, 0-1000, 每次震动循环播放的间隔,单位ms;@param amplitude 振动强度, 1-255,1最小,255最大。此参数用于修饰HE文件,进行整体的强度信号调整/缩减;@param freq 振动频率, 此参数用于修饰HE文件,进行整体的频率信号进行调整; |
| *void updateInterval(int interval) | 更新播放效果循环的时间间隔@param interval 循环间隔,interval取值区间[0,1000],单位ms |
| *void updateAmplitude(int amplitude) | 更新播放效果的振动强度,对整体效果的强度信号进行放大、缩小@param amplitude 振动强度,amplitude取值区间[1,255] |
| *void updateFrequency(int freq) | 更新播放效果的频率,对整体效果的频率信号进行放大、缩小@param freq 振动频率 |
| *void updateParameter(int interval, int amplitude, int freq) | 更新播放效果相关参数interval\|amplitude == -1时,表示不更新@param interval 循环间隔@param amplitude 振动强度@param freq 振动频率, 预留 |
| public void stop() | 停止播放振动效果 |
#### 调用示例
```
if (HapticPlayer.isAvailable()) {
DynamicEffect effect = DynamicEffect.create("{xxx: xxxx}");
HapticPlayer player = new HapticPlayer(effect);
player.start(0);
player.stop();
}
```
#### HE文件格式
```
{
"Metadata": {
"Version": 1, // 版本号,整形
"Created": "2020-07-08", // 创建时间,String类型
"Description": "game haptic" // 震动效果描述,String类型
},
"Pattern":
[
{
"Event": {
"Type": "continuous", // 事件类型: continuous->持续震动。transient->简短震动
"RelativeTime": 0, // 相对开始时间, 整形, 单位ms
"Duration": 300, // 持续震动类型参数:持续时间。整形, 单位ms
"Parameters": {
"Intensity": 80, // 震动强度, 整形, [0,100]。0->平台支持的最小值, 100->平台支持的最大值。
"Frequency": 50, // 震动频率, 整形, [0,100]。0->平台支持的最小值, 100->平台支持的最大值。
"Curve": [ // 持续震动类型参数:曲线。实现上保证平滑过渡效果
{"Time": 0,"Intensity": 0, "Frequency": 25}, // 起始点,必须。time为RelativeTime,Intensity必须取值为0。
{"Time": 100, "Intensity": 0.7, "Frequency": -30},
{"Time": 200, "Intensity": 0.75, "Frequency": 90},
{"Time": 300,"Intensity": 0, "Frequency": 50} // 结束点,必须。time为Duration,Intensity必须取值为0。
]
}
}
},
{
"Event": {
"Type": "transient", // 事件类型: continuous->持续震动, transient->简短震动
"RelativeTime": 400, // 相对开始时间, 整形, 单位ms
"Parameters": {
"Intensity": 80, // 震动强度, 整形, [0,100]。0->平台支持的最小值, 100->平台支持的最大值。
"Frequency": 40 // 震动频率, 整形, [0,100]。0->平台支持的最小值, 100->平台支持的最大值。
}
}
}
]
}
```
详细说明如下:
1)He文件为json格式,包含“Metadata”字典和“Pattern”数组两部分内容;
2)Metadata字段包括振动效果的版本“Version”,创建时间“Created”,描述“Description”等基本信息;
3)具体的振动效果由“Pattern”字段描述,“Pattern”字段内容是一个“Event”数组,每个“Event”描述一个振动效果片段,不重叠;
4)“Event”效果片段
“Type”描述振动效果类型。包含两种类型:持续的振动类型”continuous”。简短振动类型” transient”。
“RelativeTime”,相对效果文件的开始时间,整形, 单位ms。
“Duration”,持续振动类型的持续时间,整形, 单位ms。
“Parameters”字段包括振动强度“Intensity”,振动频率“Frequency”。
“Curve”为效果曲线数组参数,用来描述持续振动的动态振动效果曲线,实现侧来实现动态变化效果的平滑过渡。其中起始点和结束点是必须的,都可调整频率值。中间为可选的控制点,可调频率及强度值。
“Curve“中Time为相对event的相对时间,Intensity对 Parameters中的Intensity进行修饰,取值范围为\[0,1\], 与Parameters中的Intensity相乘。Frequency对Parameters中的Frequency进行修饰,取值范围为\[-100,100\],与Parameters中的Frequency进行相加。
# 四、接入指南
#### 准备开发环境
1. 为project/build.gradle添加maven仓库
```
示例:AGP版本7.2.1 ,gradle7.3.3 maven依赖配置(*注意AGP低版本在根目录中的build.gradle中配置该maven依赖)
maven {
allowInsecureProtocol true
url 'http://nexus.itgsa.com:5566/repository/release/'
credentials {
username 'developer'
password 'developer!@#'
}
}
```
1. 为app添加sdk, project/app/build.gradle
```
dependencies {
implementation ‘gsai.sdk:hestub:1.0.0'
}
```
1. 添加振动权限(小米侧需要)
```
project/app/src/main/AndroidManifest.xml
<uses-permission android:name="android.permission.VIBRATE"></uses-permission>
```
# 五、兼容性设计
使用implementation的构建方式将sdk代码嵌入项目中。若系统不存在HapticPlayer或DynamicEffect实现时,将由stubcode中的isAvailable返回false避免兼容性问题,在开发时应先进行判断后再使用:
```
if(HapticPlayer.isAvailable()) {
do something your own
}
```
# 六、场景问题及处理
构建遇到以下错误:
FAILURE: Build failed with an exception.
\* What went wrong:
Could not determine the dependencies of task ':app:compileDebugJavaWithJavac'.
\> Could not resolve all task dependencies for configuration ':app:debugCompileClasspath'.
\> Could not resolve gsai.sdk:roiencodestub:1.0.0-SNAPSHOT.
Required by:
​ project :app
\> Could not resolve gsai.sdk:roiencodestub:1.0.0-SNAPSHOT.
\> Unable to load Maven meta-data from https://nexus.itgsa.com:5566/repository/gsai-snapshot/gsai/sdk/roiencodestub/1.0.0-SNAPSHOT/maven-metadata.xml.
\> Could not get resource 'https://nexus.itgsa.com:5566/repository/gsai-snapshot/gsai/sdk/roiencodestub/1.0.0-SNAPSHOT/maven-metadata.xml'.
\> Could not GET 'https://nexus.itgsa.com:5566/repository/gsai-snapshot/gsai/sdk/roiencodestub/1.0.0-SNAPSHOT/maven-metadata.xml'.
\> Unsupported or unrecognized SSL message
网络问题,请更换网络环境。
/build
\ No newline at end of file
plugins {
id 'com.android.application'
}
android {
compileSdk 32
defaultConfig {
applicationId "com.vivo.hapticdemo"
minSdk 24
targetSdk 32
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
implementation 'gsai.sdk:hestub:1.0.0'
implementation 'androidx.appcompat:appcompat:1.4.2'
implementation 'com.google.android.material:material:1.6.1'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
}
\ No newline at end of file
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.vivo.hapticdemo">
<uses-permission android:name="android.permission.VIBRATE" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.HapticDemo">
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
\ No newline at end of file
{
"Metadata": {
"Created": "2020-08-10",
"Description": "Haptic editor design",
"Version": 1
},
"Pattern": [
{
"Event": {
"Duration": 500,
"Parameters": {
"Curve": [
{
"Frequency": 60,
"Intensity": 0,
"Time": 0
},
{
"Frequency": 60,
"Intensity": 0.7,
"Time": 200
},
{
"Frequency": 39,
"Intensity": 0.5,
"Time": 300
},
{
"Frequency": 40,
"Intensity": 0,
"Time": 500
}
],
"Frequency": 50,
"Intensity": 100
},
"Type": "continuous",
"RelativeTime": 50
}
}
]
}
\ No newline at end of file
{
"Metadata": {
"Created": "2020-08-10",
"Description": "Haptic editor design",
"Version": 1
},
"Pattern": [
{
"Event": {
"Parameters": {
"Frequency": 5,
"Intensity": 100
},
"Type": "transient",
"RelativeTime": 0
}
}
]
}
\ No newline at end of file
package com.vivo.hapticdemo;
import android.annotation.SuppressLint;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.ImageView;
@SuppressLint("AppCompatCustomView")
public class DragView extends ImageView {
private int width;
private int height;
private int maxWidth;
private int maxHeight;
private Context context;
private float downX;
private float downY;
public void setMaxMoveWidthAndHeight(int maxWidth, int maxHeight) {
this.maxWidth = maxWidth;
this.maxHeight = maxHeight;
}
private OnViewMoveUpListener onViewMoveUpListener;
private OnViewMoveUpListener onViewMoveUpSbListener;
public void setOnViewMoveUpListener(OnViewMoveUpListener onViewMoveUpListener) {
this.onViewMoveUpListener = onViewMoveUpListener;
}
public void setOnViewMoveUpSbListener(OnViewMoveUpListener onViewMoveUpListener) {
this.onViewMoveUpSbListener = onViewMoveUpListener;
}
public DragView(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
width = getMeasuredWidth();
height = getMeasuredHeight();
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
return super.dispatchTouchEvent(event);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
super.onTouchEvent(event);
if (this.isEnabled()) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
setPressed(true);
downX = event.getX();
downY = event.getY();
if (null != onViewMoveUpListener) {
onViewMoveUpListener.onViewDown();
}
break;
case MotionEvent.ACTION_MOVE:
float moveX = event.getX() - downX;
float moveY = event.getY() - downY;
int left, right, top, bottom;
if (Math.abs(moveX) > 0 || Math.abs(moveY) > 0) {
left = (int) (getLeft() + moveX);
right = left + width;
top = (int) (getTop() + moveY);
bottom = top + height;
if (left > -width / 2 && left < maxWidth - width / 2 && top > -width / 2 && top < maxHeight - width / 2) {
this.layout(left, top, right, bottom);
if (null != onViewMoveUpListener) {
onViewMoveUpListener.onViewMove();
}
if (null != onViewMoveUpSbListener) {
onViewMoveUpSbListener.onViewMove();
}
}
}
break;
case MotionEvent.ACTION_UP:
if (null != onViewMoveUpListener) {
onViewMoveUpListener.onViewMoveUp();
}
setPressed(false);
break;
case MotionEvent.ACTION_CANCEL:
setPressed(false);
break;
}
return true;
}
return false;
}
public interface OnViewMoveUpListener {
void onViewMoveUp();
void onViewMove();
void onViewDown();
}
}
package com.vivo.hapticdemo;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Path;
import android.util.AttributeSet;
import android.view.View;
public class DrawRelativeLayout extends View {
private int mDrawType = 0; // 绘制类型
private Paint mPaint = new Paint(); // 创建一个画笔对象
private float mInstensity, mSharpness, mAttack, mRelease, mDuration;
public DrawRelativeLayout(Context context) {
this(context, null);
}
public DrawRelativeLayout(Context context, AttributeSet attrs) {
super(context, attrs);
mPaint.setAntiAlias(true); // 设置画笔为无锯齿
mPaint.setDither(true); // 设置画笔为防抖动
mPaint.setColor(getResources().getColor(R.color.colorPrimary)); // 设置画笔的颜色
mPaint.setStrokeWidth(3); // 设置画笔的线宽
mPaint.setStyle(Style.FILL); // 设置画笔的类型。STROKE表示空心,FILL表示实心
mPaint.setColor(getResources().getColor(R.color.colorPrimary));
}
// onDraw方法在绘制下级视图之前调用
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
float ctrl_X1;
float ctrl_Y1;
float ctrl_X2;
float ctrl_Y2;
int width = getMeasuredWidth(); // 获得布局的实际宽度
int height = getMeasuredHeight(); // 获得布局的实际高度
int left = getLeft();
int right = getRight();
int top = getTop();
int bot = getBottom();
right = right - left;
bot = bot - top;
left = 0;
top = 0;
if (width > 0 && height > 0) {
Path path1 = new Path();
if (mDrawType == 0) {
mSharpness = 1 - mSharpness;
ctrl_X1 = right / (4f + mSharpness * 4);
ctrl_Y1 = (bot * (1 - mInstensity) + (bot - bot * (1 - mInstensity)) / 2) +
mSharpness * (bot - (bot * (1 - mInstensity) + (bot - bot * (1 - mInstensity)) / 2));
ctrl_X2 = right / (4f + mSharpness * 4);
ctrl_Y2 = (bot * (1 - mInstensity) + (bot - bot * (1 - mInstensity)) / 2) -
mSharpness * (bot - (bot * (1 - mInstensity) + (bot - bot * (1 - mInstensity)) / 2));
path1.reset();
path1.moveTo(left, bot);
path1.cubicTo(ctrl_X1, ctrl_Y1, ctrl_X2, ctrl_Y2, right / 2f, bot * (1 - mInstensity));
ctrl_X1 = (3 + mSharpness * 4) * right / (4f + mSharpness * 4);
ctrl_Y1 = (bot * (1 - mInstensity) + (bot - bot * (1 - mInstensity)) / 2) -
mSharpness * (bot - (bot * (1 - mInstensity) + (bot - bot * (1 - mInstensity)) / 2));
ctrl_X2 = (3 + mSharpness * 4) * right / (4f + mSharpness * 4);
ctrl_Y2 = (bot * (1 - mInstensity) + (bot - bot * (1 - mInstensity)) / 2) +
mSharpness * (bot - (bot * (1 - mInstensity) + (bot - bot * (1 - mInstensity)) / 2));
path1.cubicTo(ctrl_X1, ctrl_Y1, ctrl_X2, ctrl_Y2, right, bot);
path1.lineTo(left, bot);
path1.close();
} else if (mDrawType == 1) {
path1.moveTo(left, bot);
path1.lineTo(right * mAttack, top);
path1.lineTo(right * mAttack + (right - right * mAttack) * (1 - mRelease), top);
path1.lineTo(right, bot);
path1.lineTo(left, bot);
path1.close();
}
canvas.drawPath(path1, mPaint);
}
}
// dispatchDraw方法在绘制下级视图之前调用
protected void dispatchDraw(Canvas canvas) {
}
// 设置绘制类型
public void setDrawType(float instensity, float sharpness) {
// 背景置为白色,目的是把画布擦干净
mInstensity = instensity;
mSharpness = sharpness;
mDrawType = 0;
// 立即重新绘图,此时会触发onDraw方法和dispatchDraw方法
invalidate();
}
// 设置绘制类型
public void setDrawFade(float attack, float release, float duration) {
// 背景置为白色,目的是把画布擦干净
mAttack = attack;
mRelease = release;
mDuration = duration;
mDrawType = 1;
// 立即重新绘图,此时会触发onDraw方法和dispatchDraw方法
invalidate();
}
}
package com.vivo.hapticdemo;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.widget.RelativeLayout;
public class DrawWaveView extends RelativeLayout implements DragView.OnViewMoveUpListener {
public static final String TAG = "DrawWaveView";
public static final int INITIALVALUE = -1;
private RelativeLayout mDrawLayout;
private DragView dragViewLeft, dragViewRight;
int mPointStart_x = 48, mPointStart_y = 471;
int mPoint0_x = 48, mPoint0_y = 471;
int mPoint1_x, mPoint1_y;
int mPoint2_x, mPoint2_y;
int mPoint3_x = INITIALVALUE, mPoint3_y = 471;
int mPointEnd_x = INITIALVALUE, mPointEnd_y = 471;
private int mPadding;
private int mHeight;
private int mWidth;
private Paint mPaint = new Paint();
private Path mPath = new Path();
private float downX, downY; //点击时的x坐标,点击时的y坐标
public DrawWaveView(Context context) {
super(context);
init(context);
}
public DrawWaveView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public DrawWaveView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
private void init(Context context) {
Log.d(TAG, "init enter");
setWillNotDraw(false);
View view = LayoutInflater.from(context).inflate(R.layout.draw_wave_layout, this);
mDrawLayout = view.findViewById(R.id.draw_layout);
dragViewLeft = view.findViewById(R.id.drag_view_left);
dragViewRight = view.findViewById(R.id.drag_view_right);
dragViewLeft.setOnViewMoveUpListener(this);
dragViewRight.setOnViewMoveUpListener(this);
mPaint.setAntiAlias(true); // 设置画笔为无锯齿
mPaint.setDither(true); // 设置画笔为防抖动
mPaint.setColor(getResources().getColor(R.color.colorPrimary)); // 设置画笔的颜色
mPaint.setStrokeWidth(3); // 设置画笔的线宽
mPaint.setStyle(Paint.Style.FILL); // 设置画笔的类型。STROKE表示空心,FILL表示实心
mPaint.setColor(getResources().getColor(R.color.colorPrimary));
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
Log.d(TAG, "onMeasure enter");
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
mPadding = (int) getResources().getDimension(R.dimen.drag_layout_padding);
mHeight = mDrawLayout.getMeasuredHeight();
mWidth = mDrawLayout.getMeasuredWidth();
Log.d(TAG, "onMeasure height:" + mHeight);
Log.d(TAG, "onMeasure width:" + mWidth);
dragViewLeft.setMaxMoveWidthAndHeight(mWidth, mHeight);
dragViewRight.setMaxMoveWidthAndHeight(mWidth, mHeight);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Log.d(TAG, "onDraw");
int width = mDrawLayout.getMeasuredWidth();
int height = mDrawLayout.getMeasuredHeight();
int left = mDrawLayout.getLeft();
int right = mDrawLayout.getRight();
int top = mDrawLayout.getTop();
int bottom = mDrawLayout.getBottom();
int dragWidth = dragViewLeft.getMeasuredWidth();
int dragHeight = dragViewLeft.getMeasuredHeight();
int leftDragLeft = dragViewLeft.getLeft();
int leftDragRight = dragViewLeft.getRight();
int leftDragTop = dragViewLeft.getTop();
int leftDragBottom = dragViewLeft.getBottom();
int rightDragLeft = dragViewRight.getLeft();
int rightDragRight = dragViewRight.getRight();
int rightDragTop = dragViewRight.getTop();
int rightDragBottom = dragViewRight.getBottom();
if (dragViewLeft.isPressed()) {
if (leftDragLeft > rightDragLeft) {
rightDragLeft = leftDragLeft;
rightDragRight = leftDragLeft + dragWidth;
dragViewRight.layout(rightDragLeft, rightDragTop, rightDragRight, rightDragBottom);
}
} else if (dragViewRight.isPressed()) {
if (leftDragLeft > rightDragLeft) {
leftDragLeft = rightDragLeft;
leftDragRight = rightDragLeft + dragWidth;
dragViewLeft.layout(leftDragLeft, leftDragTop, leftDragRight, leftDragBottom);
}
}
right = right - left + mPadding;
bottom = bottom - top + mPadding;
left = mPadding;
top = mPadding;
setPointStart(left, mPointStart_y);
setPoint0(mPoint0_x, mPoint0_y);
setPoint1(leftDragLeft + mPadding + dragWidth / 2, leftDragTop + mPadding + dragHeight / 2);
setPoint2(rightDragLeft + mPadding + dragWidth / 2, rightDragTop + mPadding + dragHeight / 2);
if (mPoint3_x == INITIALVALUE || mPointEnd_x == INITIALVALUE) {
mPoint3_x = mDrawLayout.getRight();
mPointEnd_x = mDrawLayout.getRight();
}
setPoint3(mPoint3_x, mPoint3_y);
setPointEnd(mPointEnd_x, mPointEnd_y);
setPath();
canvas.drawPath(mPath, mPaint);
}
public void setPointStart(int pointStart_x, int pointStart_y) {
mPointStart_x = mDrawLayout.getLeft();
mPointStart_y = pointStart_y;
}
public void setPoint0(int point_x, int point_y) {
mPoint0_x = point_x;
mPoint0_y = point_y;
}
public void setPoint1(int point_x, int point_y) {
mPoint1_x = point_x;
mPoint1_y = point_y;
}
public void setPoint2(int point_x, int point_y) {
mPoint2_x = point_x;
mPoint2_y = point_y;
}
public void setPoint3(int point_x, int point_y) {
mPoint3_x = point_x;
mPoint3_y = point_y;
}
public void setPointEnd(int pointEnd_x, int pointEnd_y) {
mPointEnd_x = pointEnd_x;
mPointEnd_y = pointEnd_y;
}
public void setPath() {
mPath.reset();
mPath.moveTo(mDrawLayout.getLeft(), mDrawLayout.getBottom());
mPath.lineTo(mPoint0_x, mPoint0_y);
mPath.lineTo(mPoint1_x, mPoint1_y);
mPath.lineTo(mPoint2_x, mPoint2_y);
mPath.lineTo(mPoint3_x, mPoint3_y);
mPath.lineTo(mPointEnd_x, mHeight + mPadding);
mPath.close();
}
public void drawWithPoints(int pointStart_y, int point1_x, int point1_y, int point2_x, int point2_y, int pointEnd_y, int duration) {
Log.d(TAG, "drawWithPoints enter pointStart_y = " + pointStart_y + ", pointEnd_y = " + pointEnd_y);
Log.d(TAG, "drawWithPoints enter point1_x = " + point1_x + ", point1_y = " + point1_y + ", point2_x = " + point2_x + ", point2_y = " + point2_y);
int Left_l = point1_x * mWidth / 5000 - dragViewLeft.getMeasuredWidth() / 2;
int Left_t = ((100 - point1_y) * mHeight / 100) - dragViewLeft.getMeasuredHeight() / 2;
int Left_r = Left_l + dragViewLeft.getMeasuredWidth();
int Left_b = Left_t + dragViewLeft.getMeasuredHeight();
dragViewLeft.layout(Left_l, Left_t, Left_r, Left_b);
int Right_l = point2_x * mWidth / 5000 - dragViewLeft.getMeasuredWidth() / 2;
int Right_t = ((100 - point2_y) * mHeight / 100) - dragViewLeft.getMeasuredHeight() / 2;
int Right_r = Right_l + dragViewLeft.getMeasuredWidth();
int Right_b = Right_t + dragViewLeft.getMeasuredHeight();
dragViewRight.layout(Right_l, Right_t, Right_r, Right_b);
setPoint0(mDrawLayout.getLeft(), ((100 - pointStart_y) * mHeight / 100) + mPadding);
setPoint3(mDrawLayout.getLeft() + duration * mDrawLayout.getWidth() / 5000, ((100 - pointEnd_y) * mHeight / 100) + mPadding);
setPointEnd(mDrawLayout.getLeft() + duration * mDrawLayout.getWidth() / 5000, mDrawLayout.getBottom());
invalidate();
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
float downX = ev.getX(); // 点击触屏时的x坐标 用于离开屏幕时的x坐标作计算
float downY = ev.getY(); // 点击触屏时的y坐标 用于离开屏幕时的y坐标作计算
if (downX > mDrawLayout.getLeft() && downX < mDrawLayout.getRight() && downY > mDrawLayout.getTop() && downY < mDrawLayout.getBottom()) {
Log.d(TAG, "dispatchTouchEvent : in mDrawLayout,ingonre");
getParent().requestDisallowInterceptTouchEvent(true);
}
return super.dispatchTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
float downX = event.getX(); // 点击触屏时的x坐标 用于离开屏幕时的x坐标作计算
float downY = event.getY(); // 点击触屏时的y坐标 用于离开屏幕时的y坐标作计算
if (downX > mDrawLayout.getLeft() && downX < mDrawLayout.getRight() && downY > mDrawLayout.getTop() && downY < mDrawLayout.getBottom()) {
Log.d(TAG, "onTouchEvevt : in mDrawLayout,ingonre");
return true;
}
return super.onTouchEvent(event);
}
@Override
public void onViewMoveUp() {
}
@Override
public void onViewMove() {
invalidate();
}
@Override
public void onViewDown() {
}
}
package com.vivo.hapticdemo;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;
import androidx.viewpager.widget.PagerTabStrip;
import androidx.viewpager.widget.ViewPager;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.res.AssetManager;
import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.os.DynamicEffect;
import android.os.HapticPlayer;
import android.util.Log;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.RelativeLayout;
import android.widget.SeekBar;
import android.widget.TextView;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.text.DecimalFormat;
import java.util.ArrayList;
public class MainActivity extends AppCompatActivity {
public static final String TAG = "HapticDemo";
private Context mContext;
private View mRootView, mViewShort, mViewLong;
private DrawRelativeLayout drl_shrot, drl_long_base, drl_long_fade;
private TextView tv_relativetime, tv_instensity, tv_frequency;
private float relativetime_s = 0, intensity_s = 0, frequency_s = 0;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//初始化标题栏
LayoutInflater inflater = LayoutInflater.from(this);
mRootView = inflater.inflate(R.layout.activity_main, null, false);
setContentView(mRootView);
//设置屏幕常亮
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
Log.d(TAG, "OnCreat enter!");
mContext = getApplicationContext();
Boolean fileExit = checkFileExit(mContext.getFilesDir().getAbsolutePath() + "/res/example.he");
Boolean fileExit_1 = checkFileExit(mContext.getFilesDir().getAbsolutePath() + "/res/continuous_example.he");
if (!fileExit || !fileExit_1) {
new Thread(new Runnable() {
@Override
public void run() {
//复制assertsm目录下文件
copyAssert("vibeffectHe", mContext.getFilesDir().getAbsolutePath() + "/res");
//changeFileAccess(mContext.getFilesDir().getAbsolutePath() + "/res");
}
}).start();
}
InterfaceInit();
ShortHandle();
new LongViewInit(mContext, mViewLong);
}
@SuppressLint("InflateParams")
void InterfaceInit() {
PagerTabStrip pts = findViewById(R.id.haptic_title);
pts.setTextSize(TypedValue.COMPLEX_UNIT_SP, 25);
pts.setTextColor(Color.WHITE);
pts.setTabIndicatorColor(Color.WHITE);
LayoutInflater inflater = getLayoutInflater();
mViewShort = inflater.inflate(R.layout.haptic_short, null);
mViewLong = inflater.inflate(R.layout.haptic_long, null);
ArrayList<PageInfo> mViewList = new ArrayList<PageInfo>();
PageInfo short_mode = new PageInfo();
PageInfo long_mode = new PageInfo();
short_mode.title = "short";
short_mode.view = mViewShort;
long_mode.title = "continuous";
long_mode.view = mViewLong;
mViewList.add(short_mode);
mViewList.add(long_mode);
ModeAdapter ma = new ModeAdapter(mViewList);
ViewPager vp = findViewById(R.id.vp_head);
vp.setAdapter(ma);
}
void ShortHandle() {
drl_shrot = mViewShort.findViewById(R.id.drl_short);
drl_shrot.setDrawType(intensity_s, frequency_s);
tv_relativetime = mViewShort.findViewById(R.id.tv_relativetime);
tv_instensity = mViewShort.findViewById(R.id.tv_intensity);
tv_frequency = mViewShort.findViewById(R.id.tv_frequency);
SeekBar sb_relativetime = mViewShort.findViewById(R.id.sb_relativetime);
sb_relativetime.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@SuppressLint("SetTextI18n")
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
DecimalFormat df = new DecimalFormat("#");
relativetime_s = seekBar.getProgress();
tv_relativetime.setText("relativetime:" + " " + df.format(relativetime_s));
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
SeekBar sb_instensity = mViewShort.findViewById(R.id.sb_intensity);
sb_instensity.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@SuppressLint("SetTextI18n")
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
DecimalFormat df = new DecimalFormat("#");
intensity_s = (float) seekBar.getProgress();
tv_instensity.setText("intensity:" + " " + df.format(intensity_s));
drl_shrot.setDrawType(intensity_s / 100f, frequency_s / 100f);
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
SeekBar sb_frequency = mViewShort.findViewById(R.id.sb_frequency);
sb_frequency.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@SuppressLint("SetTextI18n")
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
DecimalFormat df = new DecimalFormat("#");
frequency_s = (float) seekBar.getProgress();
tv_frequency.setText("frequency:" + " " + df.format(frequency_s));
drl_shrot.setDrawType(intensity_s / 100f, frequency_s / 100f);
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
Button short_tap = mViewShort.findViewById(R.id.btn_short);
short_tap.setOnClickListener(new View.OnClickListener() {
@RequiresApi(api = Build.VERSION_CODES.N)
@Override
public void onClick(View v) {
try {
Log.d(TAG, "[palyShort called] param: ,realtivetime =" + relativetime_s + " intensity = " + intensity_s + ",frequency = " + frequency_s);
if (HapticPlayer.isAvailable()) {
//String temp = getJson(mContext, "vibeffectHe/" + effectname);
// 调用Haptic震动
String temp = generateHeJson((int) relativetime_s, (int) intensity_s, (int) frequency_s);
DynamicEffect dynamicEffect = DynamicEffect.create(temp);
HapticPlayer mHapticPlayer = new HapticPlayer(dynamicEffect);
mHapticPlayer.start(1);
} else {
Log.d(TAG, "HapticPlayer is not Available");
}
} catch (Exception e) {
Log.d(TAG, "palyShort called failed");
e.printStackTrace();
}
}
});
}
private String generateHeJson(int relativetime, int intensity, int frequency) throws JSONException {
StringBuilder stringBuilder = new StringBuilder();
//使用IO流读取json文件内容
try {
BufferedReader bf = new BufferedReader(new FileReader(mContext.getFilesDir().getAbsolutePath() + "/res/example.he"));
String s = null;
while ((s = bf.readLine()) != null) {//使用readLine方法,一次读一行
stringBuilder.append(s.trim());
}
} catch (IOException e) {
e.printStackTrace();
}
Log.d(TAG, stringBuilder.toString());
JSONObject query = new JSONObject(stringBuilder.toString());
if (query.getJSONArray("Pattern") != null) {
JSONArray pattern = query.getJSONArray("Pattern");
for (int i = 0; i < pattern.length(); i++) {
JSONObject patternObject = pattern.getJSONObject(i);
if (patternObject.getJSONObject("Event") != null) {
patternObject.getJSONObject("Event").put("RelativeTime", relativetime);
patternObject.getJSONObject("Event").getJSONObject("Parameters").put("Intensity", intensity);
patternObject.getJSONObject("Event").getJSONObject("Parameters").put("Frequency", frequency);
}
}
}
String newJsonStr = query.toString();
Log.d(TAG, newJsonStr);
return newJsonStr;
}
/**
* 复制Assert文件夹及其中的文件到某个路径
*
* @param newPath oldPath 资源路径 如:vibeffectxml
* @param newPath String 复制后的路径 如:data/user/0/com.test/res
* @return <code>true</code> if and only if the directory and files were copied;
* <code>false</code> otherwise
*/
public boolean copyAssert(String oldPath, String newPath) {
try {
Log.d(TAG, "copyFolder enter .parm :oldPath:" + oldPath + " ,newPath:" + newPath);
AssetManager assetManager = mContext.getAssets();
String files[] = assetManager.list(oldPath);
if (files == null) {
Log.d(TAG, "files[] is null");
return false;
}
for (int i = 0; i < files.length; i++) {
Log.d(TAG, "file length is " + files.length + "files[]:" + files[i]);
}
String temp;
if (files.length > 0) {//如果是子文件夹
File newFile = new File(newPath);
if (!newFile.exists()) {
if (!newFile.mkdirs()) {
Log.e("TAG", "copyFolder: cannot create directory.");
return false;
}
}
for (String filename : files) {
temp = oldPath + File.separator + filename;
copyAssert(oldPath + File.separator + filename, newPath + File.separator + filename);
}
} else {
//FileInputStream fileInputStream = new FileInputStream(temp);
InputStream fileInputStream = assetManager.open(oldPath);
FileOutputStream fileOutputStream = new FileOutputStream(newPath);
byte[] buffer = new byte[1024];
int byteRead;
while ((byteRead = fileInputStream.read(buffer)) != -1) {
fileOutputStream.write(buffer, 0, byteRead);
}
fileInputStream.close();
fileOutputStream.flush();
fileOutputStream.close();
Log.d(TAG, "copy " + oldPath + "to res/ success.");
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
private Boolean checkFileExit(String dirPath) {
File newFile = new File(dirPath);
if (!newFile.exists()) {
Log.e("TAG", "directory is not exit!");
return false;
}
return true;
}
}
class LongViewInit implements DragView.OnViewMoveUpListener {
public static final String TAG = "HapticDemo-LongViewInit";
private Context mContext;
private View mViewLong;
private DrawWaveView dwl_long;
private TextView tv_instensity_start, tv_instensity_end;
private TextView tv_relativetime_1, tv_instensity_1, tv_frequency_1;
private TextView tv_relativetime_2, tv_instensity_2, tv_frequency_2;
private TextView tv_duration;
private float intensity_start = 0, intensity_end = 0;
private float relativetime_1 = 0, intensity_1 = 0, frequency_1 = 0;
private float relativetime_2 = 0, intensity_2 = 0, frequency_2 = 0;
private float duration = 5000;
private SeekBar sb_instensity_start;
private SeekBar sb_relativetime_1, sb_instensity_1, sb_frequency_1;
private SeekBar sb_relativetime_2, sb_instensity_2, sb_frequency_2;
private SeekBar sb_instensity_end;
private SeekBar sb_duration;
private DragView dragViewLeft, dragViewRight;
@RequiresApi(api = Build.VERSION_CODES.O)
public LongViewInit(Context context, View view) {
Log.d(TAG, "LongViewInit enter");
mContext = context;
mViewLong = view;
dwl_long = mViewLong.findViewById(R.id.dw1_long);
dragViewLeft = dwl_long.findViewById(R.id.drag_view_left);
dragViewRight = dwl_long.findViewById(R.id.drag_view_right);
dragViewLeft.setOnViewMoveUpSbListener(this);
dragViewRight.setOnViewMoveUpSbListener(this);
PointStartHandle();
Point1Handle();
Point2Handle();
PointEndHandle();
ButtonInit();
}
public void PointStartHandle() {
tv_instensity_start = mViewLong.findViewById(R.id.tv_intensity_long_start);
sb_instensity_start = mViewLong.findViewById(R.id.sb_intensity_long_start);
intensity_start = (float) sb_instensity_start.getProgress();
sb_instensity_start.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
public boolean pressedStatus;
@SuppressLint("SetTextI18n")
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
DecimalFormat df = new DecimalFormat("#");
intensity_start = (float) seekBar.getProgress();
tv_instensity_start.setText("intensity:" + " " + df.format(intensity_start));
if (pressedStatus) {
dwl_long.drawWithPoints((int) intensity_start, (int) relativetime_1, (int) intensity_1,
(int) relativetime_2, (int) intensity_2, (int) intensity_end, (int) duration);
}
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
pressedStatus = true;
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
pressedStatus = false;
}
public boolean getPressed() {
return pressedStatus;
}
});
}
public void Point1Handle() {
tv_relativetime_1 = mViewLong.findViewById(R.id.tv_relatime_long_1);
tv_instensity_1 = mViewLong.findViewById(R.id.tv_intensity_long_1);
tv_frequency_1 = mViewLong.findViewById(R.id.tv_frequency_long_1);
sb_relativetime_1 = mViewLong.findViewById(R.id.sb_relatime_long_1);
relativetime_1 = sb_relativetime_1.getProgress();
sb_relativetime_1.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
public boolean pressedStatus;
@SuppressLint("SetTextI18n")
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
DecimalFormat df = new DecimalFormat("#");
relativetime_1 = seekBar.getProgress();
tv_relativetime_1.setText("relativetime:" + " " + df.format(relativetime_1));
if (pressedStatus) {
dwl_long.drawWithPoints((int) intensity_start, (int) relativetime_1, (int) intensity_1,
(int) relativetime_2, (int) intensity_2, (int) intensity_end, (int) duration);
}
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
pressedStatus = true;
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
pressedStatus = false;
}
public boolean getPressed() {
return pressedStatus;
}
});
sb_instensity_1 = mViewLong.findViewById(R.id.sb_intensity_long_1);
intensity_1 = (float) sb_instensity_1.getProgress();
sb_instensity_1.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
public boolean pressedStatus;
@SuppressLint("SetTextI18n")
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
DecimalFormat df = new DecimalFormat("#");
intensity_1 = (float) seekBar.getProgress();
tv_instensity_1.setText("intensity:" + " " + df.format(intensity_1));
if (pressedStatus) {
dwl_long.drawWithPoints((int) intensity_start, (int) relativetime_1, (int) intensity_1,
(int) relativetime_2, (int) intensity_2, (int) intensity_end, (int) duration);
}
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
pressedStatus = true;
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
pressedStatus = false;
}
public boolean getPressed() {
return pressedStatus;
}
});
sb_frequency_1 = mViewLong.findViewById(R.id.sb_frequency_long_1);
frequency_1 = (float) sb_frequency_1.getProgress();
sb_frequency_1.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
public boolean pressedStatus;
@SuppressLint("SetTextI18n")
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
DecimalFormat df = new DecimalFormat("#");
frequency_1 = (float) seekBar.getProgress();
tv_frequency_1.setText("frequency:" + " " + df.format(frequency_1));
if (pressedStatus) {
dwl_long.drawWithPoints((int) intensity_start, (int) relativetime_1, (int) intensity_1,
(int) relativetime_2, (int) intensity_2, (int) intensity_end, (int) duration);
}
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
pressedStatus = true;
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
pressedStatus = false;
}
public boolean getPressed() {
return pressedStatus;
}
});
}
public void Point2Handle() {
tv_relativetime_2 = mViewLong.findViewById(R.id.tv_relatime_long_2);
tv_instensity_2 = mViewLong.findViewById(R.id.tv_intensity_long_2);
tv_frequency_2 = mViewLong.findViewById(R.id.tv_frequency_long_2);
sb_relativetime_2 = mViewLong.findViewById(R.id.sb_relatime_long_2);
relativetime_2 = sb_relativetime_2.getProgress();
sb_relativetime_2.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
public boolean pressedStatus;
@SuppressLint("SetTextI18n")
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
DecimalFormat df = new DecimalFormat("#");
relativetime_2 = seekBar.getProgress();
tv_relativetime_2.setText("relativetime:" + " " + df.format(relativetime_2));
if (pressedStatus) {
dwl_long.drawWithPoints((int) intensity_start, (int) relativetime_1, (int) intensity_1,
(int) relativetime_2, (int) intensity_2, (int) intensity_end, (int) duration);
}
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
pressedStatus = true;
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
pressedStatus = false;
}
public boolean getPressed() {
return pressedStatus;
}
});
sb_instensity_2 = mViewLong.findViewById(R.id.sb_intensity_long_2);
intensity_2 = (float) sb_instensity_2.getProgress();
sb_instensity_2.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
public boolean pressedStatus;
@SuppressLint("SetTextI18n")
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
DecimalFormat df = new DecimalFormat("#");
intensity_2 = (float) seekBar.getProgress();
tv_instensity_2.setText("intensity:" + " " + df.format(intensity_2));
if (pressedStatus) {
dwl_long.drawWithPoints((int) intensity_start, (int) relativetime_1, (int) intensity_1,
(int) relativetime_2, (int) intensity_2, (int) intensity_end, (int) duration);
}
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
pressedStatus = true;
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
pressedStatus = false;
}
public boolean getPressed() {
return pressedStatus;
}
});
sb_frequency_2 = mViewLong.findViewById(R.id.sb_frequency_long_2);
frequency_2 = (float) sb_frequency_2.getProgress();
sb_frequency_2.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
public boolean pressedStatus;
@SuppressLint("SetTextI18n")
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
DecimalFormat df = new DecimalFormat("#");
frequency_2 = (float) seekBar.getProgress();
tv_frequency_2.setText("frequency:" + " " + df.format(frequency_2));
if (pressedStatus) {
dwl_long.drawWithPoints((int) intensity_start, (int) relativetime_1, (int) intensity_1,
(int) relativetime_2, (int) intensity_2, (int) intensity_end, (int) duration);
}
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
pressedStatus = true;
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
pressedStatus = false;
}
public boolean getPressed() {
return pressedStatus;
}
});
}
public void PointEndHandle() {
tv_instensity_end = mViewLong.findViewById(R.id.tv_intensity_long_end);
sb_instensity_end = mViewLong.findViewById(R.id.sb_intensity_long_end);
//第四个点强度为0,不可设置
sb_instensity_end.setClickable(false);
intensity_end = (float) sb_instensity_end.getProgress();
sb_instensity_end.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
public boolean pressedStatus;
@SuppressLint("SetTextI18n")
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
DecimalFormat df = new DecimalFormat("#");
intensity_end = (float) seekBar.getProgress();
tv_instensity_end.setText("intensity:" + " " + df.format(intensity_end));
if (pressedStatus) {
dwl_long.drawWithPoints((int) intensity_start, (int) relativetime_1, (int) intensity_1,
(int) relativetime_2, (int) intensity_2, (int) intensity_end, (int) duration);
}
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
pressedStatus = true;
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
pressedStatus = false;
}
public boolean getPressed() {
return pressedStatus;
}
});
}
@RequiresApi(api = Build.VERSION_CODES.O)
public void ButtonInit() {
sb_duration = mViewLong.findViewById(R.id.sb_duration);
tv_duration = mViewLong.findViewById(R.id.tv_duration);
sb_duration.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
public boolean pressedStatus;
@SuppressLint("SetTextI18n")
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
DecimalFormat df = new DecimalFormat("#");
duration = (float) seekBar.getProgress();
tv_duration.setText("duration:" + " " + df.format(duration));
//动态改变point1 时间进度条
//float temp_1 = (float) sb_relativetime_1.getProgress() / (float) sb_relativetime_1.getMax();
sb_relativetime_1.setMax(seekBar.getProgress());
//tv_relativetime_1.setText("relativetime:" + " " + df.format(sb_relativetime_1.getMax() * temp_1));
//sb_relativetime_1.setProgress((int)(sb_relativetime_1.getMax() * temp_1));
//动态改变point2 时间进度条
//float temp_2 = (float) sb_relativetime_2.getProgress() / (float) sb_relativetime_2.getMax();
sb_relativetime_2.setMax(seekBar.getProgress());
//tv_relativetime_2.setText("relativetime:" + " " + df.format(sb_relativetime_2.getMax() * temp_2));
//sb_relativetime_2.setProgress((int)(sb_relativetime_2.getMax() * temp_2));
dwl_long.drawWithPoints((int) intensity_start, (int) relativetime_1, (int) intensity_1,
(int) relativetime_2, (int) intensity_2, (int) intensity_end, (int) duration);
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
pressedStatus = true;
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
pressedStatus = false;
}
public boolean getPressed() {
return pressedStatus;
}
});
Button long_tap = mViewLong.findViewById(R.id.btn_long);
long_tap.setOnClickListener(new View.OnClickListener() {
@RequiresApi(api = Build.VERSION_CODES.N)
@Override
public void onClick(View v) {
try {
Log.d(TAG, "[Rich Continuous called] ,duration = " + duration);
Log.d(TAG, "[Rich Continuous called] param0: ,intensity = " + intensity_start + ",frequency = " + frequency_1 + " realtivetime = 0");
Log.d(TAG, "[Rich Continuous called] param1: ,intensity = " + intensity_1 + ",frequency = " + frequency_1 + " realtivetime =" + relativetime_1);
Log.d(TAG, "[Rich Continuous called] param2: ,intensity = " + intensity_2 + ",frequency = " + frequency_2 + " realtivetime =" + relativetime_2);
Log.d(TAG, "[Rich Continuous called] param3: ,intensity = " + intensity_end + ",frequency = " + frequency_2 + " realtivetime = " + duration);
if (HapticPlayer.isAvailable()) {
//String temp = getJson(mContext, "vibeffectHe/" + effectname);
// 调用Haptic震动
String temp = generateContinuousHeJson((int) duration, (int) intensity_start, (int) relativetime_1, (int) intensity_1, (int) frequency_1, (int) relativetime_2, (int) intensity_2, (int) frequency_2, (int) intensity_end);
DynamicEffect dynamicEffect = DynamicEffect.create(temp);
HapticPlayer mHapticPlayer = new HapticPlayer(dynamicEffect);
mHapticPlayer.start(1);
} else {
Log.d(TAG, "HapticPlayer is not Available");
}
} catch (Exception e) {
Log.d(TAG, "palyShort called failed");
e.printStackTrace();
}
}
});
}
private String generateContinuousHeJson(int duration, int intensity_0, int relativetime_1, int intensity_1, int frequency_1, int relativetime_2, int intensity_2, int frequency_2, int intensity_3) throws JSONException {
StringBuilder stringBuilder = new StringBuilder();
//使用IO流读取json文件内容
try {
BufferedReader bf = new BufferedReader(new FileReader(mContext.getFilesDir().getAbsolutePath() + "/res/continuous_example.he"));
String s = null;
while ((s = bf.readLine()) != null) {//使用readLine方法,一次读一行
stringBuilder.append(s.trim());
}
} catch (IOException e) {
e.printStackTrace();
}
JSONObject query = new JSONObject(stringBuilder.toString());
DecimalFormat df = new DecimalFormat("#.##");
//for every pattern
if (query.getJSONArray("Pattern") != null) {
JSONArray pattern = query.getJSONArray("Pattern");
for (int i = 0; i < pattern.length(); i++) {
JSONObject patternObject = pattern.getJSONObject(i);
if (patternObject.getJSONObject("Event") != null) {
patternObject.getJSONObject("Event").put("Duration", duration);
//for every curve
if (patternObject.getJSONObject("Event").getJSONObject("Parameters").getJSONArray("Curve") != null) {
JSONArray curve = patternObject.getJSONObject("Event").getJSONObject("Parameters").getJSONArray("Curve");
for (int j = 0; j < curve.length(); j++) {
JSONObject curveObject = curve.getJSONObject(j);
if (j == 0) {
curveObject.put("Frequency", frequency_1 - 50);
curveObject.put("Intensity", df.format((float) intensity_0 / 100));
curveObject.put("Time", 0);
} else if (j == 1) {
curveObject.put("Frequency", frequency_1 - 50);
curveObject.put("Intensity", df.format((float) intensity_1 / 100));
curveObject.put("Time", relativetime_1);
} else if (j == 2) {
curveObject.put("Frequency", frequency_2 - 50);
curveObject.put("Intensity", df.format((float) intensity_2 / 100));
curveObject.put("Time", relativetime_2 - 1);
} else if (j == 3) {
curveObject.put("Frequency", frequency_2 - 50);
curveObject.put("Intensity", df.format((float) intensity_3 / 100));
curveObject.put("Time", duration);
}
}
patternObject.getJSONObject("Event").getJSONObject("Parameters").put("Intensity", 100);
patternObject.getJSONObject("Event").getJSONObject("Parameters").put("Frequency", 50);
}
}
}
}
String newJsonStr = query.toString();
Log.d(TAG, newJsonStr);
return newJsonStr;
}
@Override
public void onViewMoveUp() {
}
@RequiresApi(api = Build.VERSION_CODES.N)
@Override
public void onViewMove() {
RelativeLayout mDrawLayout = dwl_long.findViewById(R.id.draw_layout);
Log.d(TAG, "dragViewLeft.getLeft() = " + dragViewLeft.getLeft());
Log.d(TAG, "mViewLong.getWidth() = " + mViewLong.getWidth());
Log.d(TAG, "mViewLong.getBottom() = " + mViewLong.getBottom());
Log.d(TAG, "dragViewLeft.getTop() = " + dragViewLeft.getTop());
int point1_relatime = (dragViewLeft.getLeft() + dragViewLeft.getWidth() / 2) * 5000 / mDrawLayout.getWidth();
int point1_intensity = (mDrawLayout.getHeight() - dragViewLeft.getTop() - dragViewLeft.getHeight() / 2) * 100 / mDrawLayout.getHeight();
int point2_relatime = (dragViewRight.getLeft() + dragViewRight.getWidth() / 2) * 5000 / mDrawLayout.getWidth();
int point2_intensity = (mDrawLayout.getHeight() - dragViewRight.getTop() - dragViewLeft.getHeight() / 2) * 100 / mDrawLayout.getHeight();
sb_relativetime_1.setProgress(point1_relatime, true);
sb_instensity_1.setProgress(point1_intensity, true);
sb_relativetime_2.setProgress(point2_relatime, true);
sb_instensity_2.setProgress(point2_intensity, true);
}
@Override
public void onViewDown() {
}
}
class PageInfo {
public View view;
public String title;
}
\ No newline at end of file
package com.vivo.hapticdemo;
import android.view.View;
import android.view.ViewGroup;
import androidx.viewpager.widget.PagerAdapter;
import java.util.ArrayList;
public class ModeAdapter extends PagerAdapter {
private ArrayList<PageInfo> mViewList;
public ModeAdapter(ArrayList<PageInfo> mView) {
mViewList = mView;
}
public boolean isViewFromObject(View arg0, Object arg1) {
// TODO Auto-generated method stub
return arg0 == arg1;
}
@Override
public int getCount() {
// TODO Auto-generated method stub
return mViewList.size();
}
public void destroyItem(ViewGroup container, int position,
Object object) {
// TODO Auto-generated method stub
container.removeView(mViewList.get(position).view);
}
public Object instantiateItem(ViewGroup container, int position) {
// TODO Auto-generated method stub
container.addView(mViewList.get(position).view);
return mViewList.get(position).view;
}
public CharSequence getPageTitle(int position) {
return mViewList.get(position).title;
}
}
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
<aapt:attr name="android:fillColor">
<gradient
android:endX="85.84757"
android:endY="92.4963"
android:startX="42.9492"
android:startY="49.59793"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
android:strokeWidth="1"
android:strokeColor="#00000000" />
</vector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="@dimen/drag_point_size" />
<size
android:width="@dimen/drag_point_size"
android:height="@dimen/drag_point_size" />
<solid android:color="@color/colorFoth" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<stroke
android:width="@dimen/drag_layout_bg_stoke"
android:color="@color/colorFoth" />
<!-- <solid android:color="@color/colorbg"/>-->
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path
android:fillColor="#3DDC84"
android:pathData="M0,0h108v108h-108z" />
<path
android:fillColor="#00000000"
android:pathData="M9,0L9,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,0L19,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,0L29,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,0L39,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,0L49,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,0L59,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,0L69,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,0L79,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M89,0L89,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M99,0L99,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,9L108,9"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,19L108,19"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,29L108,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,39L108,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,49L108,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,59L108,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,69L108,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,79L108,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,89L108,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,99L108,99"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,29L89,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,39L89,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,49L89,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,59L89,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,69L89,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,79L89,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,19L29,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,19L39,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,19L49,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,19L59,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,19L69,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,19L79,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
</vector>
<?xml version="1.0" encoding="utf-8"?>
<layer-list
xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@android:id/background">
<shape>
<corners android:radius="3dp" />
<solid android:color="#ECF0F1" />
</shape>
</item>
<item android:id="@android:id/secondaryProgress">
<clip>
<shape>
<corners android:radius="3dp" />
<solid android:color="#C6CACE" />
</shape>
</clip>
</item>
<item android:id="@android:id/progress">
<clip>
<shape>
<corners android:radius="3dp" />
<solid android:color="@color/colorPrimary" />
</shape>
</clip>
</item>
</layer-list>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<!-- solid表示远的填充色 -->
<solid android:color="@color/colorPrimary" />
<!-- stroke则代表远的边框线 -->
<stroke
android:width="1dp"
android:color="@color/colorPrimary" />
<!-- size控制高宽 -->
<size
android:height="20dp"
android:width="20dp" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 指定了形状内部的填充颜色 -->
<solid android:color="#f2f1f6" />
<!-- 指定了形状边线的粗细与颜色 -->
<stroke
android:width="1dp"
android:color="#f2f1f6" />
<!-- 指定了形状四个圆角的半径 -->
<corners
android:bottomLeftRadius="20sp"
android:bottomRightRadius="20sp"
android:topLeftRadius="20sp"
android:topRightRadius="20sp" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 指定了形状内部的填充颜色 -->
<solid android:color="@color/colorDisableBtn" />
<!-- 指定了形状边线的粗细与颜色 -->
<stroke
android:width="1dp"
android:color="@color/colorDisableBtn" />
<!-- 指定了形状四个圆角的半径 -->
<corners
android:bottomLeftRadius="20dp"
android:bottomRightRadius="20dp"
android:topLeftRadius="20dp"
android:topRightRadius="20dp" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 指定了形状内部的填充颜色 -->
<solid android:color="@color/colorFir" />
<!-- 指定了形状边线的粗细与颜色 -->
<stroke
android:width="1dp"
android:color="@color/colorFir" />
<!-- 指定了形状四个圆角的半径 -->
<corners
android:bottomLeftRadius="20dp"
android:bottomRightRadius="20dp"
android:topLeftRadius="20dp"
android:topRightRadius="20dp" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 指定了形状内部的填充颜色 -->
<solid android:color="@color/colorFith" />
<!-- 指定了形状边线的粗细与颜色 -->
<stroke
android:width="1dp"
android:color="@color/colorFith" />
<!-- 指定了形状四个圆角的半径 -->
<corners
android:bottomLeftRadius="20dp"
android:bottomRightRadius="20dp"
android:topLeftRadius="20dp"
android:topRightRadius="20dp" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 指定了形状内部的填充颜色 -->
<solid android:color="@color/colorFoth" />
<!-- 指定了形状边线的粗细与颜色 -->
<stroke
android:width="1dp"
android:color="@color/colorFoth" />
<!-- 指定了形状四个圆角的半径 -->
<corners
android:bottomLeftRadius="20dp"
android:bottomRightRadius="20dp"
android:topLeftRadius="20dp"
android:topRightRadius="20dp" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 指定了形状内部的填充颜色 -->
<solid android:color="@color/colorSec" />
<!-- 指定了形状边线的粗细与颜色 -->
<stroke
android:width="1dp"
android:color="@color/colorSec" />
<!-- 指定了形状四个圆角的半径 -->
<corners
android:bottomLeftRadius="20dp"
android:bottomRightRadius="20dp"
android:topLeftRadius="20dp"
android:topRightRadius="20dp" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 指定了形状内部的填充颜色 -->
<solid android:color="@color/colorThi" />
<!-- 指定了形状边线的粗细与颜色 -->
<stroke
android:width="1dp"
android:color="@color/colorThi" />
<!-- 指定了形状四个圆角的半径 -->
<corners
android:bottomLeftRadius="20dp"
android:bottomRightRadius="20dp"
android:topLeftRadius="20dp"
android:topRightRadius="20dp" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 指定了形状内部的填充颜色 -->
<solid android:color="@color/colorPrimary" />
<!-- 指定了形状边线的粗细与颜色 -->
<stroke
android:width="1dp"
android:color="@color/colorPrimary" />
<!-- 指定了形状四个圆角的半径 -->
<corners
android:bottomLeftRadius="20dp"
android:bottomRightRadius="20dp"
android:topLeftRadius="20dp"
android:topRightRadius="20dp" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 指定了形状内部的填充颜色 -->
<solid android:color="#f2f1f6" />
<!-- 指定了形状边线的粗细与颜色 -->
<stroke
android:width="1dp"
android:color="@color/colorPrimary" />
<!-- 指定了形状四个圆角的半径 -->
<corners
android:bottomLeftRadius="0sp"
android:bottomRightRadius="0sp"
android:topLeftRadius="0sp"
android:topRightRadius="0sp" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="true" android:drawable="@drawable/switch_on"/>
<item android:drawable="@drawable/switch_off"/>
</selector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.viewpager.widget.ViewPager
android:id="@+id/vp_head"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.viewpager.widget.PagerTabStrip
android:id="@+id/haptic_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@color/colorPrimary" />
</androidx.viewpager.widget.ViewPager>
</LinearLayout>
</LinearLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="@dimen/drag_layout_padding">
<RelativeLayout
android:id="@+id/draw_layout"
android:layout_width="375dp"
android:layout_height="141dp"
android:background="@drawable/draw_layout_bg">
<com.vivo.hapticdemo.DragView
android:id="@+id/drag_view_left"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="125dp"
android:src="@drawable/drag_point_up" />
<com.vivo.hapticdemo.DragView
android:id="@+id/drag_view_right"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="250dp"
android:src="@drawable/drag_point_up" />
</RelativeLayout>
</RelativeLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<com.vivo.hapticdemo.DrawWaveView
android:id="@+id/dw1_long"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:orientation="horizontal">
<TextView
android:id="@+id/tv_point_start"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="Pointstart"
android:textSize="15sp"
android:textStyle="bold"
android:textColorHint="@color/app_color_theme_1"
android:layout_marginLeft="20dp"
android:textColor="#bbbbbb"/>
<TextView
android:id="@+id/tv_point_end"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="Pointend"
android:textSize="15sp"
android:textStyle="bold"
android:textColorHint="@color/app_color_theme_1"
android:layout_marginLeft="20dp"
android:textColor="#bbbbbb"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<LinearLayout
android:layout_width="0sp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical"
android:background="@drawable/draw_layout_bg">
<TextView
android:id="@+id/tv_intensity_long_start"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="intensity: 0"
android:textSize="15sp"
android:layout_marginStart="20dp"
android:textColor="#bbbbbb"/>
<SeekBar
android:id="@+id/sb_intensity_long_start"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:maxHeight="2dp"
android:minHeight="2dp"
android:paddingBottom="3dp"
android:paddingLeft="12dp"
android:paddingRight="12dp"
android:paddingTop="3dp"
android:progressDrawable="@drawable/seek_bar_progress_shape"
android:thumb="@drawable/seekbar_thumb_shape"
android:max="100" />
</LinearLayout>
<LinearLayout
android:layout_width="0sp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical"
android:background="@drawable/draw_layout_bg">
<TextView
android:id="@+id/tv_intensity_long_end"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="intensity: 0"
android:layout_marginLeft="20dp"
android:textSize="15sp"
android:textColor="#bbbbbb"/>
<SeekBar
android:id="@+id/sb_intensity_long_end"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:maxHeight="2dp"
android:minHeight="2dp"
android:paddingBottom="3dp"
android:paddingLeft="12dp"
android:paddingRight="12dp"
android:paddingTop="3dp"
android:progressDrawable="@drawable/seek_bar_progress_shape"
android:thumb="@drawable/seekbar_thumb_shape"
android:max="100" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:orientation="horizontal">
<TextView
android:id="@+id/tv_point_1"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="PointLeft"
android:textSize="15sp"
android:textStyle="bold"
android:textColorHint="@color/app_color_theme_1"
android:layout_marginLeft="20dp"
android:textColor="#bbbbbb"/>
<TextView
android:id="@+id/tv_point_2"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="PointRight"
android:textSize="15sp"
android:textStyle="bold"
android:textColorHint="@color/app_color_theme_1"
android:layout_marginLeft="20dp"
android:textColor="#bbbbbb"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<LinearLayout
android:layout_width="0sp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical"
android:background="@drawable/draw_layout_bg">
<TextView
android:id="@+id/tv_relatime_long_1"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="relatime: 1666"
android:textSize="15sp"
android:layout_marginLeft="20dp"
android:textColor="#bbbbbb"/>
<SeekBar
android:id="@+id/sb_relatime_long_1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toLeftOf="@+id/text1"
android:maxHeight="2dp"
android:minHeight="2dp"
android:paddingBottom="3dp"
android:paddingLeft="12dp"
android:paddingRight="12dp"
android:paddingTop="3dp"
android:progressDrawable="@drawable/seek_bar_progress_shape"
android:thumb="@drawable/seekbar_thumb_shape"
android:max="5000"
android:progress="1666"/>
<TextView
android:id="@+id/tv_intensity_long_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="intensity: 50"
android:textSize="15sp"
android:layout_marginLeft="20dp"
android:textColor="#bbbbbb"/>
<SeekBar
android:id="@+id/sb_intensity_long_1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toLeftOf="@+id/text1"
android:maxHeight="2dp"
android:minHeight="2dp"
android:paddingBottom="3dp"
android:paddingLeft="12dp"
android:paddingRight="12dp"
android:paddingTop="3dp"
android:progressDrawable="@drawable/seek_bar_progress_shape"
android:thumb="@drawable/seekbar_thumb_shape"
android:max="100"
android:progress="50"/>
<TextView
android:id="@+id/tv_frequency_long_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="frequency: 50"
android:textSize="15sp"
android:layout_marginLeft="20dp"
android:textColor="#bbbbbb"/>
<SeekBar
android:id="@+id/sb_frequency_long_1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toLeftOf="@+id/text1"
android:maxHeight="2dp"
android:minHeight="2dp"
android:paddingBottom="3dp"
android:paddingLeft="12dp"
android:paddingRight="12dp"
android:paddingTop="3dp"
android:progressDrawable="@drawable/seek_bar_progress_shape"
android:thumb="@drawable/seekbar_thumb_shape"
android:max="100"
android:progress="50"/>
</LinearLayout>
<LinearLayout
android:layout_width="0sp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical"
android:background="@drawable/draw_layout_bg">
<TextView
android:id="@+id/tv_relatime_long_2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="relatime: 3332"
android:layout_marginLeft="20dp"
android:textSize="15sp"
android:textColor="#bbbbbb"/>
<SeekBar
android:id="@+id/sb_relatime_long_2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toLeftOf="@+id/text1"
android:maxHeight="2dp"
android:minHeight="2dp"
android:paddingBottom="3dp"
android:paddingLeft="12dp"
android:paddingRight="12dp"
android:paddingTop="3dp"
android:progressDrawable="@drawable/seek_bar_progress_shape"
android:thumb="@drawable/seekbar_thumb_shape"
android:max="5000"
android:progress="3332"/>
<TextView
android:id="@+id/tv_intensity_long_2"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="intensity: 50"
android:layout_marginLeft="20dp"
android:textSize="15sp"
android:textColor="#bbbbbb"/>
<SeekBar
android:id="@+id/sb_intensity_long_2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toLeftOf="@+id/text1"
android:maxHeight="2dp"
android:minHeight="2dp"
android:paddingBottom="3dp"
android:paddingLeft="12dp"
android:paddingRight="12dp"
android:paddingTop="3dp"
android:progressDrawable="@drawable/seek_bar_progress_shape"
android:thumb="@drawable/seekbar_thumb_shape"
android:max="100"
android:progress="50"/>
<TextView
android:id="@+id/tv_frequency_long_2"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="frequency: 50"
android:layout_marginLeft="20dp"
android:textSize="15sp"
android:textColor="#bbbbbb"/>
<SeekBar
android:id="@+id/sb_frequency_long_2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:maxHeight="2dp"
android:minHeight="2dp"
android:paddingBottom="3dp"
android:paddingLeft="12dp"
android:paddingRight="12dp"
android:paddingTop="3dp"
android:progressDrawable="@drawable/seek_bar_progress_shape"
android:thumb="@drawable/seekbar_thumb_shape"
android:max="100"
android:progress="50"/>
</LinearLayout>
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/tv_duration"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="duration: 5000"
android:layout_marginTop="10dp"
android:layout_marginLeft="20dp"
android:textSize="15sp"
android:textColor="#bbbbbb"/>
<SeekBar
android:id="@+id/sb_duration"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:maxHeight="2dp"
android:minHeight="2dp"
android:paddingBottom="3dp"
android:paddingLeft="12dp"
android:paddingRight="12dp"
android:paddingTop="3dp"
android:progressDrawable="@drawable/seek_bar_progress_shape"
android:thumb="@drawable/seekbar_thumb_shape"
android:max="5000"
android:progress="5000"/>
</LinearLayout>
<Button
android:id="@+id/btn_long"
android:layout_width="match_parent"
android:layout_height="70sp"
android:layout_marginTop="20sp"
android:layout_marginLeft="20sp"
android:layout_marginRight="20sp"
android:background="@drawable/shape_but"
android:text="Tap"
android:textColor="#ffffff"
android:textSize="15sp"/>
</LinearLayout>
\ No newline at end of file
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:custom="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.vivo.hapticdemo.DrawRelativeLayout
android:id="@+id/drl_short"
android:layout_width="match_parent"
android:layout_height="200sp"
android:layout_marginTop="20sp"
android:layout_marginLeft="20sp"
android:layout_marginRight="20sp"
android:background="@drawable/shape_rect">
</com.vivo.hapticdemo.DrawRelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="50sp"
android:orientation="horizontal"
android:layout_marginTop="20sp"
android:visibility="gone"
android:layout_marginLeft="20sp"
android:layout_marginRight="20sp"
android:background="@drawable/shape_brk_backgrount">
<TextView
android:id="@+id/tv_brake"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="brake status"
android:layout_marginLeft="20dp"
android:layout_marginTop="10sp"
android:layout_alignParentLeft="true"
android:textSize="18sp"
android:textColor="#aaaaaa"/>
<CheckBox
android:id="@+id/ck_status"
android:layout_width="60dp"
android:layout_height="30dp"
android:checked="true"
android:layout_marginRight="20dp"
android:layout_marginTop="10sp"
android:background="@drawable/switch_selector"
android:button="@null"
android:layout_alignParentRight="true"
android:layout_gravity="right"/>
</RelativeLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/tv_relativetime"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="relativetime: 0"
android:textSize="15sp"
android:layout_marginTop="20dp"
android:layout_marginLeft="20dp"
android:textColor="#bbbbbb"/>
<SeekBar
android:id="@+id/sb_relativetime"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toLeftOf="@+id/text1"
android:maxHeight="2dp"
android:minHeight="2dp"
android:paddingBottom="3dp"
android:paddingLeft="12dp"
android:paddingRight="12dp"
android:paddingTop="3dp"
android:progressDrawable="@drawable/seek_bar_progress_shape"
android:thumb="@drawable/seekbar_thumb_shape"
android:max="100" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/tv_intensity"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="intensity: 0"
android:layout_marginLeft="20dp"
android:textSize="15sp"
android:textColor="#bbbbbb"/>
<SeekBar
android:id="@+id/sb_intensity"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toLeftOf="@+id/text1"
android:maxHeight="2dp"
android:minHeight="2dp"
android:paddingBottom="3dp"
android:paddingLeft="12dp"
android:paddingRight="12dp"
android:paddingTop="3dp"
android:progressDrawable="@drawable/seek_bar_progress_shape"
android:thumb="@drawable/seekbar_thumb_shape"
android:max="100" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/tv_frequency"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="frequency: 0"
android:textSize="15sp"
android:layout_marginLeft="20dp"
android:textColor="#bbbbbb"/>
<SeekBar
android:id="@+id/sb_frequency"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toLeftOf="@+id/text1"
android:maxHeight="2dp"
android:minHeight="2dp"
android:paddingBottom="3dp"
android:paddingLeft="12dp"
android:paddingRight="12dp"
android:paddingTop="3dp"
android:progressDrawable="@drawable/seek_bar_progress_shape"
android:thumb="@drawable/seekbar_thumb_shape"
android:max="100" />
</LinearLayout>
<Button
android:id="@+id/btn_short"
android:layout_width="match_parent"
android:layout_height="70sp"
android:layout_marginTop="40sp"
android:layout_marginLeft="20sp"
android:layout_marginRight="20sp"
android:background="@drawable/shape_but"
android:text="Tap"
android:textColor="#ffffff"
android:textSize="15sp"/>
</LinearLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>
\ No newline at end of file
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. -->
<style name="Theme.HapticDemo" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
<!-- Primary brand color. -->
<item name="colorPrimary">@color/purple_200</item>
<item name="colorPrimaryVariant">@color/purple_700</item>
<item name="colorOnPrimary">@color/black</item>
<!-- Secondary brand color. -->
<item name="colorSecondary">@color/teal_200</item>
<item name="colorSecondaryVariant">@color/teal_200</item>
<item name="colorOnSecondary">@color/black</item>
<!-- Status bar color. -->
<item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
<!-- Customize your theme here. -->
</style>
</resources>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="purple_200">#FFBB86FC</color>
<color name="purple_500">#03A9F4</color>
<color name="purple_700">#2196F3</color>
<color name="teal_200">#FF03DAC5</color>
<color name="teal_700">#FF018786</color>
<color name="black">#FF000000</color>
<color name="white">#FFFFFFFF</color>
<color name="colorPrimary">#299EE3</color>
<color name="colorFir">#81b7dc</color>
<color name="colorSec">#81dca7</color>
<color name="colorThi">#dc8189</color>
<color name="colorFoth">#45cdc0</color>
<color name="colorFith">#d481dc</color>
<color name="colorDisableBtn">#d2cecd</color>
<color name="colorbg">#F4F3F3</color>
<color name="app_color_theme_1">#EF5362</color> <!-- Grapefruit -->
<color name="app_color_theme_2">#FE6D4B</color> <!-- Bittersweet -->
<color name="app_color_theme_3">#FFCF47</color> <!-- Sunflower -->
<color name="app_color_theme_4">#9FD661</color> <!-- Grass -->
<color name="app_color_theme_5">#3FD0AD</color> <!-- Mint -->
<color name="app_color_theme_6">#2BBDF3</color> <!-- Aqua -->
<color name="app_color_theme_7">#5A9AEF</color> <!-- Blue Jeans -->
<color name="app_color_theme_8">#AC8FEF</color> <!-- Lavender -->
<color name="app_color_theme_9">#EE85C1</color> <!-- Pink Rose -->
</resources>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="drag_point_size">16dp</dimen>
<dimen name="drag_layout_padding">16dp</dimen>
<dimen name="drag_layout_bg_stoke">1dp</dimen>
</resources>
<resources>
<string name="app_name">HapticDemo</string>
</resources>
\ No newline at end of file
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. -->
<style name="Theme.HapticDemo" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
<!-- Primary brand color. -->
<item name="colorPrimary">@color/purple_500</item>
<item name="colorPrimaryVariant">@color/purple_700</item>
<item name="colorOnPrimary">@color/white</item>
<!-- Secondary brand color. -->
<item name="colorSecondary">@color/teal_200</item>
<item name="colorSecondaryVariant">@color/teal_700</item>
<item name="colorOnSecondary">@color/black</item>
<!-- Status bar color. -->
<item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
<!-- Customize your theme here. -->
</style>
</resources>
\ No newline at end of file
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
google()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:7.0.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.20"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
\ No newline at end of file
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx1024m -Dfile.encoding=UTF-8
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
# AndroidX package structure to make it clearer which packages are bundled with the
# Android operating system, and which are packaged with your app"s APK
# https://developer.android.com/topic/libraries/support-library/androidx-rn
android.useAndroidX=true
# Enables namespacing of each library's R class so that its R class includes only the
# resources declared in the library itself and none from the library's dependencies,
# thereby reducing the size of the R class for that library
android.nonTransitiveRClass=true
# Automatically convert third-party libraries to use AndroidX
android.enableJetifier=true
# Kotlin code style for this project: "official" or "obsolete":
kotlin.code.style=official
android.injected.studio.version.check=false
\ No newline at end of file
#Thu Aug 11 14:58:11 CST 2022
distributionBase=GRADLE_USER_HOME
distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-bin.zip
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
#!/usr/bin/env sh
#
# Copyright 2015 the original author or authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn () {
echo "$*"
}
die () {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=`expr $i + 1`
done
case $i in
0) set -- ;;
1) set -- "$args0" ;;
2) set -- "$args0" "$args1" ;;
3) set -- "$args0" "$args1" "$args2" ;;
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=`save "$@"`
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
exec "$JAVACMD" "$@"
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega
pluginManagement {
repositories {
gradlePluginPortal()
google()
mavenCentral()
maven {
allowInsecureProtocol true
url 'http://nexus.itgsa.com:5566/repository/release/'
credentials {
username 'developer'
password 'developer!@#'
}
}
}
}
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
maven {
allowInsecureProtocol true
url 'http://nexus.itgsa.com:5566/repository/release/'
credentials {
username 'developer'
password 'developer!@#'
}
}
}
}
rootProject.name = "hapticdemo"
include ':app'
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment