Commit ae5e04a0 authored by Administrator's avatar Administrator

init project

parents
Pipeline #1832 failed with stages
*.iml
.gradle
/local.properties
.idea/
.DS_Store
build/
/captures
.externalNativeBuild
.cxx
*.apk
ratelConfig.properties
\ No newline at end of file
# 虚拟定位app,基于平头哥插件
/build
\ No newline at end of file
apply plugin: 'com.android.application'
android {
compileSdkVersion 28
buildToolsVersion "28.0.3"
defaultConfig {
applicationId "com.virjar.ratel.virtuallocation"
minSdkVersion 19
targetSdkVersion 28
versionCode 20200825
versionName "v1.0"
archivesBaseName = "JDY_${versionName}".replace(' ', '_')
ndk {
abiFilters "armeabi-v7a", "arm64-v8a"//, "x86","arm64-v8a","x86_64"
}
}
signingConfigs {
release {
storeFile rootProject.file('script/hermes_key')
storePassword "hermes"
keyAlias "hermes"
keyPassword "hermes"
}
}
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.release
}
debug {
minifyEnabled false
signingConfig signingConfigs.release
}
}
sourceSets {
main {
jniLibs.srcDir 'libs'
}
}
lintOptions {
abortOnError false
}
}
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation fileTree(include: ['*.aar'], dir: 'libs')
implementation 'com.android.support:appcompat-v7:28.0.0'
//implementation 'com.android.support.constraint:constraint-layout:2.0.0-rc1'
implementation 'com.android.support:cardview-v7:28.0.0'
implementation 'com.android.support:recyclerview-v7:28.0.0'
implementation 'com.android.support:design:28.0.0'
compileOnly 'com.virjar:ratel-api:1.3.4'
}
#!/usr/bin/env sh
##############################################################################
##
## 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=""
# 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, switch paths to Windows format before running java
if $cygwin ; 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=$((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"
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi
exec "$JAVACMD" "$@"
@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 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=
@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 init
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 init
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
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
: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 %CMD_LINE_ARGS%
: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
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in D:\DevSoft\Android\AndroidSDK/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# 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
-keep class com.baidu.** {*;}
-keep class vi.com.** {*;}
-keep class mapsdkvi.com.gdi.bgl.android.** {*;}
-keep class top.littlerich.virtuallocation.XPosedPlugin{*;}
-dontwarn com.baidu.**
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.virjar.ratel.virtuallocation">
<!-- 这个权限用于进行网络定位 -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!-- 这个权限用于访问GPS定位 -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<!-- 用于访问wifi网络信息,wifi信息会用于进行网络定位 -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<!-- 获取网络状态,根据网络状态切换进行数据请求网络转换 -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- 写外置存储。如果开发者使用了离线地图,并且数据写在外置存储区域,则需要申请该权限 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- 读取外置存储。如果开发者使用了so动态加载功能并且把so文件放在了外置存储区域,则需要申请该权限,否则不需要 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<!-- 访问网络,进行地图相关业务数据请求,包括地图数据,路线规划,POI检索等 -->
<uses-permission android:name="android.permission.INTERNET" />
<!-- 调用相机,用于实现扫描二维码,预览个性化地图编辑器生成的个性化地图样式(开发者实际开发中地图SDK不需要该权限)-->
<uses-permission android:name="android.permission.CAMERA" />
<application
android:name="top.littlerich.virtuallocation.common.AppApplication"
android:allowBackup="true"
android:icon="@mipmap/logo_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.AppCompat.Light.NoActionBar">
<meta-data
android:name="xposedmodule"
android:value="true"/>
<!-- 模块描述 -->
<meta-data
android:name="xposeddescription"
android:value="平头哥框架的虚拟定位"/>
<!-- XposedBridgeApi的最低版本号 -->
<meta-data
android:name="xposedminversion"
android:value="54"/>
<meta-data
android:name="com.baidu.lbsapi.API_KEY"
android:value="2y88wkskaOi5fG6dM00DNgYyHtmxhhXo"/>
<service
android:name="com.baidu.location.f"
android:enabled="true"
android:process=":remote">
</service>
<activity android:name="top.littlerich.virtuallocation.activity.MainActivity"
android:screenOrientation="portrait"
>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:name="top.littlerich.virtuallocation.activity.AboutActivity">
</activity>
<activity android:name="top.littlerich.virtuallocation.activity.PreciseLocationActivity">
</activity>
<activity android:name="top.littlerich.virtuallocation.activity.AppsActivity">
</activity>
<provider
android:name="top.littlerich.virtuallocation.service.GPSContentProvider"
android:authorities="com.virjar.ratel.virtuallocation"
android:exported="true"
android:grantUriPermissions="true"
tools:ignore="ExportedContentProvider" />
</application>
</manifest>
\ No newline at end of file
top.littlerich.virtuallocation.XPosedPlugin
\ No newline at end of file
package top.littlerich.virtuallocation.activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.view.Window;
import com.virjar.ratel.virtuallocation.R;
import top.littlerich.virtuallocation.view.TopBanner;
public class AboutActivity extends AppCompatActivity {
TopBanner mTopbanner;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_about);
initViews();
bindListener();
}
private void initViews() {
mTopbanner = (TopBanner) findViewById(R.id.topbanner);
}
private void bindListener() {
mTopbanner.setTopBannerListener(new TopBanner.OnTopBannerListener() {
@Override
public void leftClick(View v) {
finish();
}
@Override
public void rightClick(View v) {
}
});
}
public static void openActivity(Context conetxt){
Intent intent = new Intent(conetxt, AboutActivity.class);
conetxt.startActivity(intent);
}
}
package top.littlerich.virtuallocation.activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.Toast;
import com.virjar.ratel.virtuallocation.R;
import java.util.List;
import top.littlerich.virtuallocation.adapter.AppAdapter;
import top.littlerich.virtuallocation.model.MyAppInfo;
import top.littlerich.virtuallocation.util.ApkTool;
import top.littlerich.virtuallocation.view.TopBanner;
public class AppsActivity extends AppCompatActivity {
private RecyclerView mRecyclerView;
private LinearLayoutManager mLayoutManager;
AppAdapter mAppAdapter;
public Handler mHandler = new Handler();
private ProgressBar mProgressBar;
private TopBanner mTopbanner;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_apps);
initView();
bindListener();
//创建默认的线性LayoutManager
mLayoutManager = new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(mLayoutManager);
//如果可以确定每个item的高度是固定的,设置这个选项可以提高性能
mRecyclerView.setHasFixedSize(true);
//创建并设置Adapter
mAppAdapter = new AppAdapter();
mRecyclerView.setAdapter(mAppAdapter);
initAppList(false);
}
private void bindListener() {
mTopbanner.setTopBannerListener(new TopBanner.OnTopBannerListener() {
@Override
public void leftClick(View v) {
finish();
}
@Override
public void rightClick(View v) {
if (mProgressBar.isShown()) {
Toast.makeText(AppsActivity.this, "数据未加载完成,无法过滤!", Toast.LENGTH_SHORT).show();
} else {
mProgressBar.setVisibility(View.VISIBLE);
initAppList(true);
}
}
});
}
private void initView() {
mTopbanner = (TopBanner) findViewById(R.id.topbanner);
mRecyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);
mProgressBar = (ProgressBar) findViewById(R.id.pb_progressbar);
mProgressBar.setVisibility(View.VISIBLE);
}
private void initAppList(final boolean isFilter) {
new Thread() {
@Override
public void run() {
super.run();
//扫描得到APP列表
final List<MyAppInfo> appInfos = ApkTool.scanLocalInstallAppList(AppsActivity.this.getPackageManager(), isFilter);
mHandler.post(new Runnable() {
@Override
public void run() {
mAppAdapter.setData(appInfos);
runOnUiThread(new Runnable() {
@Override
public void run() {
mProgressBar.setVisibility(View.GONE);
}
});
}
});
}
}.start();
}
public static void openActivity(Context context) {
Intent intent = new Intent(context, AppsActivity.class);
context.startActivity(intent);
}
}
package top.littlerich.virtuallocation.activity;
import android.animation.Animator;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.AppCompatButton;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import com.virjar.ratel.virtuallocation.R;
import top.littlerich.virtuallocation.presenter.JellyInterpolator;
import top.littlerich.virtuallocation.view.TopBanner;
public class PreciseLocationActivity extends AppCompatActivity {
private EditText mLongitudeValue;
private EditText mLatitudeValue;
private AppCompatButton mBeginLocation;
private TopBanner mTopbanner;
private ProgressBar mPbLocating;
private TextView mTip;
float width;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_precise_location);
initViews();
bindListener();
}
private void bindListener() {
mBeginLocation.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
width = mBeginLocation.getMeasuredWidth();
float height = mBeginLocation.getMeasuredHeight();
inputAnimator(mBeginLocation, width, height);
} catch (NumberFormatException e) {
Toast.makeText(PreciseLocationActivity.this, "请输入正确的经纬度!", Toast.LENGTH_SHORT).show();
}
}
});
mTopbanner.setTopBannerListener(new TopBanner.OnTopBannerListener() {
@Override
public void leftClick(View v) {
finish();
}
@Override
public void rightClick(View v) {
}
});
mPbLocating.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
showTip("精确定位", View.GONE);
mPbLocating.setVisibility(View.GONE);
mBeginLocation.setVisibility(View.VISIBLE);
repaintView(mBeginLocation);
}
});
}
/**
* 使组件变回原有形状
*
* @param view
*/
private void repaintView(final View view) {
AnimatorSet set = new AnimatorSet();
ValueAnimator animator = ValueAnimator.ofFloat(width, 0);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float value = (Float) animation.getAnimatedValue();
ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) mBeginLocation
.getLayoutParams();
params.leftMargin = (int) value;
params.rightMargin = (int) value;
view.setLayoutParams(params);
}
});
ObjectAnimator animator2 = ObjectAnimator.ofFloat(view,
"scaleX", 0.5f, 1f);
set.setDuration(1000);
set.setInterpolator(new AccelerateDecelerateInterpolator());
set.playTogether(animator, animator2);
set.start();
}
private void initViews() {
mLatitudeValue = (EditText) findViewById(R.id.et_latitude);
mLongitudeValue = (EditText) findViewById(R.id.et_longitude);
mBeginLocation = (AppCompatButton) findViewById(R.id.btn_precise_location);
mTopbanner = (TopBanner) findViewById(R.id.topbanner);
mPbLocating = (ProgressBar) findViewById(R.id.pb_locating);
mTip = (TextView) findViewById(R.id.tv_tip);
}
private void inputAnimator(final View view, float w, float h) {
AnimatorSet set = new AnimatorSet();
ValueAnimator animator = ValueAnimator.ofFloat(0, w);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float value = (Float) animation.getAnimatedValue();
ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) mBeginLocation
.getLayoutParams();
params.leftMargin = (int) value;
params.rightMargin = (int) value;
view.setLayoutParams(params);
}
});
ObjectAnimator animator2 = ObjectAnimator.ofFloat(view,
"scaleX", 1f, 0.5f);
set.setDuration(1000);
set.setInterpolator(new AccelerateDecelerateInterpolator());
set.playTogether(animator, animator2);
set.start();
set.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
// TODO Auto-generated method stub
}
@Override
public void onAnimationEnd(Animator animation) {
showTip("穿越完成", View.VISIBLE);
mBeginLocation.setVisibility(View.GONE);
mPbLocating.setVisibility(View.VISIBLE);
progressAnimator(mPbLocating);
}
@Override
public void onAnimationCancel(Animator animation) {
// TODO Auto-generated method stub
}
});
}
private void showTip(String title, int isVisible) {
mTopbanner.setTitleText(title);
mTip.setVisibility(isVisible);
}
private void progressAnimator(final View view) {
PropertyValuesHolder animator = PropertyValuesHolder.ofFloat("scaleX",
0.5f, 1f);
PropertyValuesHolder animator2 = PropertyValuesHolder.ofFloat("scaleY",
0.5f, 1f);
ObjectAnimator animator3 = ObjectAnimator.ofPropertyValuesHolder(view,
animator, animator2);
animator3.setDuration(1000);
animator3.setInterpolator(new JellyInterpolator());
animator3.start();
}
public static void openActivity(Context context) {
Intent intent = new Intent(context, PreciseLocationActivity.class);
context.startActivity(intent);
}
@Override
protected void onDestroy() {
super.onDestroy();
mPbLocating.clearAnimation();
mBeginLocation.clearAnimation();
}
}
package top.littlerich.virtuallocation.adapter;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.ImageView;
import android.widget.TextView;
import com.virjar.ratel.virtuallocation.R;
import java.util.ArrayList;
import java.util.List;
import top.littlerich.virtuallocation.common.AppApplication;
import top.littlerich.virtuallocation.model.MyAppInfo;
/**
* Created by xuqingfu on 2017/4/24.
*/
public class AppAdapter extends RecyclerView.Adapter<AppAdapter.ViewHolder> {
List<MyAppInfo> mListData = new ArrayList<MyAppInfo>();
public AppAdapter() {
}
@Override
public ViewHolder onCreateViewHolder(final ViewGroup parent, int viewType) {
final View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_app_info, parent, false);
final ViewHolder viewHolder = new ViewHolder(view);
viewHolder.cbAppSelect.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
AppApplication.setAppMock(viewHolder.myAppInfo.getPkgName(), isChecked);
}
});
return viewHolder;
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
MyAppInfo myAppInfo = mListData.get(position);
holder.iv_app_icon.setImageDrawable(myAppInfo.getImage());
holder.tx_app_name.setText(myAppInfo.getAppName());
holder.tx_app_pkg.setText(myAppInfo.getPkgName());
holder.myAppInfo = myAppInfo;
holder.cbAppSelect.setChecked(
AppApplication.getAppMockStatus(myAppInfo.getPkgName())
);
}
@Override
public int getItemCount() {
return mListData != null ? mListData.size() : 0;
}
public void setData(List<MyAppInfo> myAppInfos) {
this.mListData = myAppInfos;
notifyDataSetChanged();
}
/*
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder mViewHolder;
MyAppInfo myAppInfo = mListData.get(position);
if (convertView == null) {
mViewHolder = new ViewHolder();
convertView = LayoutInflater.from(mContext).inflate(R.layout.item_app_info, null);
mViewHolder.iv_app_icon = (ImageView) convertView.findViewById(R.id.iv_app_icon);
mViewHolder.tx_app_name = (TextView) convertView.findViewById(R.id.tv_app_name);
convertView.setTag(mViewHolder);
} else {
mViewHolder = (ViewHolder) convertView.getTag();
}
mViewHolder.iv_app_icon.setImageDrawable(myAppInfo.getImage());
mViewHolder.tx_app_name.setText(myAppInfo.getAppName());
return convertView;
}*/
public static class ViewHolder extends RecyclerView.ViewHolder {
ImageView iv_app_icon;
TextView tx_app_name;
TextView tx_app_pkg;
CheckBox cbAppSelect;
MyAppInfo myAppInfo;
public ViewHolder(View itemView) {
super(itemView);
iv_app_icon = itemView.findViewById(R.id.iv_app_icon);
tx_app_name = itemView.findViewById(R.id.tv_app_name);
tx_app_pkg = itemView.findViewById(R.id.tv_app_pkg);
cbAppSelect = itemView.findViewById(R.id.cb_app_select);
}
}
}
package top.littlerich.virtuallocation.base;
import android.app.Activity;
import android.os.Bundle;
import android.support.v7.widget.Toolbar;
import android.view.LayoutInflater;
import android.view.View;
import android.view.Window;
import top.littlerich.virtuallocation.view.CustomProgressDialog;
/**
* Created by xuqingfu on 2017/4/15.
*/
public abstract class BaseActivity extends Activity {
protected View mView;
protected CustomProgressDialog progressDialog;
protected Toolbar toolbar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
Object object = getContentViewId();
if (object instanceof Integer) {
mView = LayoutInflater.from(this).inflate((Integer) object, null);
} else if (object instanceof View) {
mView = (View) object;
}
setContentView(mView);
// toolbar = (Toolbar) findViewById(R.id.toolbar);
IniView();
progressDialog = new CustomProgressDialog(this);
progressDialog.setCancelable(true);
progressDialog.setCanceledOnTouchOutside(false);
IniLister();
IniData();
}
/**
* @Title: getContentViewId
* @Description: 布局文件Id
*/
protected abstract Object getContentViewId();
/**
* @Title: IniView
* @Description: 初始化View
*/
protected abstract void IniView();
/**
* @Title: IniLister
* @Description: 初始化接口
*/
protected abstract void IniLister();
/**
* @Title: IniData
* @Description: 初始化数据
*/
protected abstract void IniData();
/**
* thisFinish 当前关闭
*/
protected abstract void thisFinish();
@Override
public void onBackPressed() {
thisFinish();
}
/**
* showProgressDialog 显示等待框
*
* @param text 显示文字
*/
public void showProgressDialog(String text) {
if (progressDialog != null) {
progressDialog.show();
progressDialog.setMessage(text);
}
}
/**
* cancelProgressDialog 取消等待框
*/
public void cancelProgressDialog() {
if (progressDialog != null && progressDialog.isShowing()) {
progressDialog.dismiss();
}
}
}
package top.littlerich.virtuallocation.base;
import android.app.Dialog;
import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import com.virjar.ratel.virtuallocation.R;
/**
* Created by xuqingfu on 2017/4/15.
*/
public abstract class BaseDialog extends Dialog {
protected View mView;
protected Context mContext;
public BaseDialog(Context context) {
this(context, R.style.clashDialog);
}
public BaseDialog(Context context, int theme) {
super(context, theme);
this.mContext = context;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LayoutInflater mLayoutInflater = LayoutInflater.from(mContext);
mView = mLayoutInflater.inflate(getContentViewId(), null);
this.setContentView(mView);
InitView();
IniListener();
InitData();
}
/**
* 初始化view变量,用于显示
*/
protected abstract int getContentViewId();
/**
* 初始化所有控件
*/
protected abstract void InitView();
/**
* 设置事件
*/
protected abstract void IniListener();
/**
* 初始化所有数据
*/
protected abstract void InitData();
}
package top.littlerich.virtuallocation.common;
import android.Manifest;
import android.app.Application;
import android.app.Service;
import android.content.Context;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.Vibrator;
import android.util.Log;
import com.baidu.mapapi.CoordType;
import com.baidu.mapapi.SDKInitializer;
import org.json.JSONObject;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import top.littlerich.virtuallocation.model.Gps;
import top.littlerich.virtuallocation.service.LocationService;
import top.littlerich.virtuallocation.util.FileUtils;
import top.littlerich.virtuallocation.util.PermissionUtil;
/**
* Created by xuqingfu on 2017/4/15.
*/
public class AppApplication extends Application {
public static final String tag = "RVLocation";
public LocationService locationService;
public Vibrator mVibrator;
private static AppApplication appApplication;
public static Gps mockGPS = null;
@Override
public void onCreate() {
super.onCreate();
appApplication = this;
/***
* 初始化定位sdk,建议在Application中创建
*/
locationService = new LocationService(getApplicationContext());
mVibrator = (Vibrator) getApplicationContext().getSystemService(Service.VIBRATOR_SERVICE);
if (PermissionUtil.checkPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
// 在使用 SDK 各组间之前初始化 context 信息,传入 ApplicationContext
SDKInitializer.initialize(this);
SDKInitializer.setCoordType(CoordType.GCJ02);
}
}
public static void setAppMock(String pkg, boolean isChecked) {
File configFile = new File(appApplication.getFilesDir(), pkg + "_status.conf");
if (isChecked) {
try {
FileWriter fileWriter = new FileWriter(configFile);
fileWriter.write("mock");
fileWriter.flush();
fileWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
} else if (configFile.exists()) {
configFile.delete();
}
}
public static boolean getAppMockStatus(String pkg) {
File configFile = new File(appApplication.getFilesDir(), pkg + "_status.conf");
return configFile.exists();
}
public static Gps getConfigGPS() {
File configFile = new File(appApplication.getFilesDir(), "mockGPS.json");
if (!configFile.exists()) {
return Config.COMPANY;
}
try {
String config = FileUtils.readLine(configFile);
JSONObject jsonObject = new JSONObject(config);
double longitude = jsonObject.optDouble("longitude");
double latitude = jsonObject.optDouble("latitude");
return new Gps(latitude, longitude, getAddress());
} catch (Exception e) {
e.printStackTrace();
return Config.COMPANY;
}
}
public static void saveConfigGPS(double longitude, double latitude) {
File configFile = new File(appApplication.getFilesDir(), "mockGPS.json");
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put("longitude", longitude);
jsonObject.put("latitude", latitude);
FileUtils.writeLine(configFile, jsonObject.toString());
} catch (Exception e) {
e.printStackTrace();
}
}
public static void storeAddress(String address) {
File configFile = new File(appApplication.getFilesDir(), "mockAddress.txt");
try {
FileUtils.writeLine(configFile, address);
} catch (Exception e) {
e.printStackTrace();
}
}
private static String getAddress() {
File configFile = new File(appApplication.getFilesDir(), "mockAddress.txt");
if (!configFile.exists()) {
return "";
}
try {
return FileUtils.readLine(configFile);
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
public static void queryMockGPS(Context context) {
try {
Bundle bundle = context.getContentResolver()
.call(Uri.parse("content://com.virjar.ratel.virtuallocation"),
"invoke", context.getPackageName(), null);
if (bundle == null) {
return;
}
double lat = bundle.getDouble("lat", -1);
double lng = bundle.getDouble("lng", -1);
String address = bundle.getString("address");
Log.i(AppApplication.tag, "queryMockGPS: " + lng + "," + lat + " " + address);
if (lat == -1 && lng == -1) {
return;
}
mockGPS = new Gps(lat, lng, address);
} catch (Exception e) {
Log.e(AppApplication.tag, "error for queryMockGPS", e);
}
}
}
\ No newline at end of file
package top.littlerich.virtuallocation.common;
import top.littlerich.virtuallocation.model.Gps;
/**
* Created by xuqingfu on 2017/5/26.
*/
public class Config {
public static final Gps SWUN = new Gps(30.6386505171,104.0492391586);
public static final Gps CAPITAL = new Gps(39.9127646676,116.3859844208);
public static final Gps COMPANY = new Gps(30.5819505065,104.0539652109);
}
package top.littlerich.virtuallocation.listener;
import com.baidu.location.BDLocation;
import com.baidu.location.BDLocationListener;
import com.baidu.mapapi.map.MapView;
import com.baidu.mapapi.model.LatLng;
import static top.littlerich.virtuallocation.activity.MainActivity.setCurrentMapLatLng;
/**
* 定位结果回调
* API: http://lbsyun.baidu.com/index.php?title=android-locsdk/guide/getloc
* Created by xuqingfu on 2017/5/3.
*/
public class AsyncLocationResultListener implements BDLocationListener {
private MapView mMapView;
boolean isFirstLoc;// 是否首次定位
//private double myGpslatitude, myGpslongitude;
public AsyncLocationResultListener(MapView mapView, boolean isFirstLoc) {
mMapView = mapView;
this.isFirstLoc = isFirstLoc;
//this.myGpslatitude = myGpslatitude;
// this.myGpslongitude = myGpslongitude;
}
@Override
public void onReceiveLocation(BDLocation location) {
// map view 销毁后不在处理新接收的位置
if (location == null || mMapView == null) {
return;
}
LatLng ll = new LatLng(location.getLatitude(), location.getLongitude());
setCurrentMapLatLng(ll);
}
}
package top.littlerich.virtuallocation.listener;
import android.content.Context;
import android.util.Log;
import android.widget.TextView;
import android.widget.Toast;
import com.baidu.mapapi.search.core.SearchResult;
import com.baidu.mapapi.search.geocode.GeoCodeResult;
import com.baidu.mapapi.search.geocode.OnGetGeoCoderResultListener;
import com.baidu.mapapi.search.geocode.ReverseGeoCodeResult;
import top.littlerich.virtuallocation.common.AppApplication;
/**
* 地理编码:1、正向地图编码 2、反向地图编码
* Created by xuqingfu on 2017/5/4.
*/
public class GeoCoderListener implements OnGetGeoCoderResultListener {
private Context mContext;
private TextView mLocationTip;
public GeoCoderListener(Context context, TextView locationTip) {
mContext = context;
mLocationTip = locationTip;
}
/**
* 搜索(根据实地信息-->经纬坐标)
*
* @param geoCodeResult
*/
@Override
public void onGetGeoCodeResult(GeoCodeResult geoCodeResult) {
}
/**
* 搜索(根据坐标-->实地信息)
*
* @param result
*/
@Override
public void onGetReverseGeoCodeResult(ReverseGeoCodeResult result) {
if (result == null || result.error != SearchResult.ERRORNO.NO_ERROR) {
Log.w(AppApplication.tag, "error:" + result);
Toast.makeText(mContext, "抱歉,未能找到结果", Toast.LENGTH_LONG).show();
return;
}
String address = String.format("%s %s", result.getAddress(), result.getSematicDescription());
AppApplication.storeAddress(address);
Log.i(AppApplication.tag, "逆地理:" + result);
mLocationTip.setText(String.format("伪造位置:%s", address));
}
}
package top.littlerich.virtuallocation.listener;
import android.util.Log;
import android.widget.Button;
import com.baidu.mapapi.map.BaiduMap;
import com.baidu.mapapi.map.MapPoi;
import com.baidu.mapapi.model.LatLng;
import top.littlerich.virtuallocation.common.AppApplication;
import static top.littlerich.virtuallocation.activity.MainActivity.setCurrentMapLatLng;
/**
* 地图单击事件监听接口
* Created by xuqingfu on 2017/5/4.
*/
public class MapClickListener implements BaiduMap.OnMapClickListener {
private Button mLocOk;
public MapClickListener(Button locOk) {
mLocOk = locOk;
}
/**
* 地图单击事件
*
* @param latLng 点击的地理坐标
*/
@Override
public void onMapClick(LatLng latLng) {
setCurrentMapLatLng(latLng);
if ("穿越完成".equals(mLocOk.getText().toString())) {
mLocOk.setText("修改位置");
}
}
/**
* 地图内 Poi 单击事件
*
* @param mapPoi 点击的 poi 信息
* @return
*/
@Override
public void onMapPoiClick(MapPoi mapPoi) {
Log.i(AppApplication.tag, "clickPOI: " + mapPoi.getPosition()
+ " name:" + mapPoi.getName() +
" uid:" + mapPoi.getUid()
);
LatLng position = mapPoi.getPosition();
this.onMapClick(position);
}
}
package top.littlerich.virtuallocation.listener;
import com.baidu.mapapi.map.BaiduMap;
import com.baidu.mapapi.map.Marker;
import static top.littlerich.virtuallocation.activity.MainActivity.setCurrentMapLatLng;
/**
* Created by xuqingfu on 2017/5/4.
*/
public class MarkerDragListener implements BaiduMap.OnMarkerDragListener {
/**
* 地图上标记拖动
* @param marker
*/
@Override
public void onMarkerDrag(Marker marker) {
}
/**
* 地图上标记拖动结束
* @param marker
*/
@Override
public void onMarkerDragEnd(Marker marker) {
setCurrentMapLatLng(marker.getPosition());
}
/**
* 地图上标记拖动开始
* @param marker
*/
@Override
public void onMarkerDragStart(Marker marker) {
}
}
package top.littlerich.virtuallocation.model;
/**
* Created by xuqingfu on 2017/5/26.
*/
public class Gps {
public double mLatitude;
public double mLongitude;
public String address;
public Gps(double latitude, double longitude) {
mLatitude = latitude;
mLongitude = longitude;
}
public Gps(double latitude, double longitude, String address) {
this(latitude, longitude);
this.address = address;
}
}
package top.littlerich.virtuallocation.model;
import android.graphics.drawable.Drawable;
/**
* Created by xuqingfu on 17/4/24.
*/
public class MyAppInfo {
private Drawable image;
private String appName;
private String pkgName;
public Drawable getImage() {
return image;
}
public void setImage(Drawable image) {
this.image = image;
}
public String getAppName() {
return appName;
}
public void setAppName(String appName) {
this.appName = appName;
}
public String getPkgName() {
return pkgName;
}
public void setPkgName(String pkgName) {
this.pkgName = pkgName;
}
}
package top.littlerich.virtuallocation.presenter;
/**
* Created by xuqingfu on 2017/5/26.
*/
public class HookApis {
private static final String TAG = "silence";
/**
* 修改高德地图的经纬度值
* @param
* @throws ClassNotFoundException
*/
public static void findMethodAmapLongitudeAndLatitude(ClassLoader classLoader) {
// try {
// Class aMapLocationClazz = classLoader.loadClass("com.amap.api.location.AMapLocation");
// XposedHelpers.findAndHookMethod(aMapLocationClazz, "getLongitude", new Object[]{new XC_MethodHook() {
// protected void beforeHookedMethod(MethodHookParam arg3) throws Throwable {
// arg3.setResult(Double.valueOf(AppApplication.mMockGps.mLongitude));
// Log.d(TAG, "修改高德地图的经纬度值:" + AppApplication.mMockGps.mLongitude + ":" + AppApplication.mMockGps.mLatitude);
// }
// }});
//
// XposedHelpers.findAndHookMethod(aMapLocationClazz, "getLatitude", new Object[]{new XC_MethodHook() {
// protected void beforeHookedMethod(MethodHookParam arg3) throws Throwable {
// arg3.setResult(Double.valueOf(AppApplication.mMockGps.mLatitude));
// }
// }});
// } catch (Exception e) {
// Log.i(TAG, "该程序无高德地图模块,无法HOOK");
// }
}
}
package top.littlerich.virtuallocation.presenter;
import android.view.animation.LinearInterpolator;
public class JellyInterpolator extends LinearInterpolator {
private float factor;
public JellyInterpolator() {
this.factor = 0.15f;
}
@Override
public float getInterpolation(float input) {
return (float) (Math.pow(2, -10 * input)
* Math.sin((input - factor / 4) * (2 * Math.PI) / factor) + 1);
}
}
//package top.littlerich.virtuallocation.presenter;
//
//import android.content.ContentResolver;
//import android.location.Location;
//import android.provider.Settings;
//
//import de.robv.android.xposed.XC_MethodHook;
//import de.robv.android.xposed.XC_MethodReplacement;
//import de.robv.android.xposed.XposedHelpers;
//import de.robv.android.xposed.callbacks.XC_LoadPackage;
//
//import static android.provider.Settings.Secure.LOCATION_MODE_SENSORS_ONLY;
//
///**
// * Created by xuqingfu on 2017/5/31.
// */
//
//public class SdkHookManager {
//
// /**
// * 判断是否开启允许ADB模拟定位功能
// */
// public static void findMethodIsFromMockProvider(){
// XposedHelpers.findAndHookMethod(Location.class, "isFromMockProvider", new XC_MethodHook() {
// @Override
// protected void afterHookedMethod(MethodHookParam param) throws Throwable {
// super.afterHookedMethod(param);
// param.setResult(false);
// }
// });
// }
//
// /**
// * 劫持判断是否使用虚拟定位
// * @param loadPackageParam
// */
// public static void findMethodGetInt(XC_LoadPackage.LoadPackageParam loadPackageParam){
// // boolean isOpen = Settings.Secure.getInt(getContentResolver(),Settings.Secure.ALLOW_MOCK_LOCATION, 0) != 0;
// XposedHelpers.findAndHookMethod("android.provider.Settings$Secure", loadPackageParam.classLoader, "getInt", ContentResolver.class, String.class, int.class, new XC_MethodHook() {
//
// /**
// * 设置返回值类型:
// * 1、gpsEnabled && networkEnabled:LOCATION_MODE_HIGH_ACCURACY
// * 2、gpsEnabled:LOCATION_MODE_SENSORS_ONLY
// * 3、networkEnabled:LOCATION_MODE_BATTERY_SAVING
// * 4、disable:LOCATION_MODE_OFF
// */
// @Override
// protected void afterHookedMethod(MethodHookParam param) throws Throwable {
// super.afterHookedMethod(param);
// param.setResult(LOCATION_MODE_SENSORS_ONLY);
// }
// });
//
// XposedHelpers.findAndHookMethod(Settings.Secure.class, "getInt", ContentResolver.class, String.class, int.class, new XC_MethodReplacement() {
// @Override
// protected Object replaceHookedMethod(MethodHookParam methodHookParam) throws Throwable {
// return LOCATION_MODE_SENSORS_ONLY;
// }
// });
// }
//
//
//
//}
package top.littlerich.virtuallocation.service;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import top.littlerich.virtuallocation.common.AppApplication;
import top.littlerich.virtuallocation.model.Gps;
public class GPSContentProvider extends ContentProvider {
@Override
public boolean onCreate() {
return false;
}
@Nullable
@Override
public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {
return null;
}
@Nullable
@Override
public String getType(@NonNull Uri uri) {
return null;
}
@Nullable
@Override
public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
return null;
}
@Override
public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
return 0;
}
@Override
public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) {
return 0;
}
@Nullable
@Override
public Bundle call(@NonNull String method, @Nullable String arg, @Nullable Bundle extras) {
//return super.call(method, arg, extras);
boolean appMockStatus = AppApplication.getAppMockStatus(arg);
Bundle bundle = new Bundle();
if (!appMockStatus) {
return bundle;
}
Gps configGPS = AppApplication.getConfigGPS();
bundle.putDouble("lat", configGPS.mLatitude);
bundle.putDouble("lng", configGPS.mLongitude);
bundle.putString("address", configGPS.address);
return bundle;
}
}
package top.littlerich.virtuallocation.service;
import android.content.Context;
import android.webkit.WebView;
import com.baidu.location.BDAbstractLocationListener;
import com.baidu.location.LocationClient;
import com.baidu.location.LocationClientOption;
import com.baidu.location.LocationClientOption.LocationMode;
/**
* 定位服务LocationClient 相关
*
* @author baidu
*/
public class LocationService {
private static LocationClient client = null;
private static LocationClientOption mOption;
private static LocationClientOption DIYoption;
private Object objLock;
/***
* 初始化 LocationClient
*
* @param locationContext
*/
public LocationService(Context locationContext) {
objLock = new Object();
synchronized (objLock) {
if (client == null) {
client = new LocationClient(locationContext);
client.setLocOption(getDefaultLocationClientOption());
}
}
}
/***
* 注册定位监听
*
* @param listener
* @return
*/
public boolean registerListener(BDAbstractLocationListener listener) {
boolean isSuccess = false;
if (listener != null) {
client.registerLocationListener(listener);
isSuccess = true;
}
return isSuccess;
}
public void unregisterListener(BDAbstractLocationListener listener) {
if (listener != null) {
client.unRegisterLocationListener(listener);
}
}
/**
* @return 获取sdk版本
*/
public String getSDKVersion() {
if (client != null) {
String version = client.getVersion();
return version;
}
return null;
}
/***
* 设置定位参数
*
* @param option
* @return isSuccessSetOption
*/
public static boolean setLocationOption(LocationClientOption option) {
boolean isSuccess = false;
if (option != null) {
if (client.isStarted()) {
client.stop();
}
DIYoption = option;
client.setLocOption(option);
}
return isSuccess;
}
/**
* 开发者应用如果有H5页面使用了百度JS接口,该接口可以辅助百度JS更好的进行定位
*
* @param webView 传入webView控件
*/
public void enableAssistanLocation(WebView webView) {
if (client != null) {
client.enableAssistantLocation(webView);
}
}
/**
* 停止H5辅助定位
*/
public void disableAssistantLocation() {
if (client != null) {
client.disableAssistantLocation();
}
}
/***
*
* @return DefaultLocationClientOption 默认O设置
*/
public LocationClientOption getDefaultLocationClientOption() {
if (mOption == null) {
mOption = new LocationClientOption();
mOption.setLocationMode(LocationMode.Hight_Accuracy); // 可选,默认高精度,设置定位模式,高精度,低功耗,仅设备
mOption.setCoorType( "bd09ll" ); // 可选,默认gcj02,设置返回的定位结果坐标系,如果配合百度地图使用,建议设置为bd09ll;
mOption.setScanSpan(3000); // 可选,默认0,即仅定位一次,设置发起连续定位请求的间隔需要大于等于1000ms才是有效的
mOption.setIsNeedAddress(true); // 可选,设置是否需要地址信息,默认不需要
mOption.setIsNeedLocationDescribe(true); // 可选,设置是否需要地址描述
mOption.setNeedDeviceDirect(false); // 可选,设置是否需要设备方向结果
mOption.setLocationNotify(false); // 可选,默认false,设置是否当gps有效时按照1S1次频率输出GPS结果
mOption.setIgnoreKillProcess(true); // 可选,默认true,定位SDK内部是一个SERVICE,并放到了独立进程,设置是否在stop
mOption.setIsNeedLocationDescribe(true); // 可选,默认false,设置是否需要位置语义化结果,可以在BDLocation
mOption.setIsNeedLocationPoiList(true); // 可选,默认false,设置是否需要POI结果,可以在BDLocation
mOption.SetIgnoreCacheException(false); // 可选,默认false,设置是否收集CRASH信息,默认收集
mOption.setOpenGps(true); // 可选,默认false,设置是否开启Gps定位
mOption.setIsNeedAltitude(false); // 可选,默认false,设置定位时是否需要海拔信息,默认不需要,除基础定位版本都可用
}
return mOption;
}
/**
* @return DIYOption 自定义Option设置
*/
public LocationClientOption getOption() {
if (DIYoption == null) {
DIYoption = new LocationClientOption();
}
return DIYoption;
}
public void start() {
synchronized (objLock) {
if (client != null && !client.isStarted()) {
client.start();
}
}
}
public void requestLocation() {
if (client != null) {
client.requestLocation();
}
}
public void stop() {
synchronized (objLock) {
if (client != null && client.isStarted()) {
client.stop();
}
}
}
public boolean isStart() {
return client.isStarted();
}
public boolean requestHotSpotState() {
return client.requestHotSpotState();
}
}
package top.littlerich.virtuallocation.service;
public class Utils {
public final static String CoorType_GCJ02 = "gcj02";
public final static String CoorType_BD09LL= "bd09ll";
public final static String CoorType_BD09MC= "bd09";
/***
*61 : GPS定位结果,GPS定位成功。
*62 : 无法获取有效定位依据,定位失败,请检查运营商网络或者wifi网络是否正常开启,尝试重新请求定位。
*63 : 网络异常,没有成功向服务器发起请求,请确认当前测试手机网络是否通畅,尝试重新请求定位。
*65 : 定位缓存的结果。
*66 : 离线定位结果。通过requestOfflineLocaiton调用时对应的返回结果。
*67 : 离线定位失败。通过requestOfflineLocaiton调用时对应的返回结果。
*68 : 网络连接失败时,查找本地离线定位时对应的返回结果。
*161: 网络定位结果,网络定位定位成功。
*162: 请求串密文解析失败。
*167: 服务端定位失败,请您检查是否禁用获取位置信息权限,尝试重新请求定位。
*502: key参数错误,请按照说明文档重新申请KEY。
*505: key不存在或者非法,请按照说明文档重新申请KEY。
*601: key服务被开发者自己禁用,请按照说明文档重新申请KEY。
*602: key mcode不匹配,您的ak配置过程中安全码设置有问题,请确保:sha1正确,“;”分号是英文状态;且包名是您当前运行应用的包名,请按照说明文档重新申请KEY。
*501~700:key验证失败,请按照说明文档重新申请KEY。
*/
public static float[] EARTH_WEIGHT = {0.1f,0.2f,0.4f,0.6f,0.8f}; // 推算计算权重_地球
//public static float[] MOON_WEIGHT = {0.0167f,0.033f,0.067f,0.1f,0.133f};
//public static float[] MARS_WEIGHT = {0.034f,0.068f,0.152f,0.228f,0.304f};
public final static int RECEIVE_TAG = 1;
public final static int DIAGNOSTIC_TAG = 2;
}
package top.littlerich.virtuallocation.util;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.util.Log;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import top.littlerich.virtuallocation.model.MyAppInfo;
/**
* 扫描本地安装的应用,工具类
* <p>
* Created by xuqingfu on 2017/4/24.
*/
public class ApkTool {
static String TAG = "ApkTool";
public static List<MyAppInfo> mLocalInstallApps = null;
public static List<MyAppInfo> scanLocalInstallAppList(PackageManager packageManager, boolean isFilter) {
List<MyAppInfo> myAppInfos = new ArrayList<MyAppInfo>();
try {
List<PackageInfo> packageInfos = packageManager.getInstalledPackages(0);
for (int i = 0; i < packageInfos.size(); i++) {
PackageInfo packageInfo = packageInfos.get(i);
//过滤掉系统app
if (isFilter && (ApplicationInfo.FLAG_SYSTEM & packageInfo.applicationInfo.flags) != 0) {
continue;
}
MyAppInfo myAppInfo = new MyAppInfo();
myAppInfo.setPkgName(packageInfo.packageName);
myAppInfo.setAppName(packageInfo.applicationInfo.loadLabel(packageManager).toString());
if (packageInfo.applicationInfo.loadIcon(packageManager) == null) {
continue;
}
String apkPathDir = packageInfo.applicationInfo.sourceDir;
try (ZipFile apkZip = new ZipFile(apkPathDir)) {
ZipEntry entry = apkZip.getEntry("assets/ratel_serialNo.txt");
if (entry == null) {
//normal apk
continue;
}
}
myAppInfo.setImage(packageInfo.applicationInfo.loadIcon(packageManager));
myAppInfos.add(myAppInfo);
}
} catch (Exception e) {
Log.e(TAG, "===============获取应用包信息失败");
}
Collections.sort(myAppInfos, new Comparator<MyAppInfo>() {
@Override
public int compare(MyAppInfo o1, MyAppInfo o2) {
return o1.getAppName().compareTo(o2.getAppName());
}
});
return myAppInfos;
}
}
package top.littlerich.virtuallocation.util;
import android.os.Build;
import android.text.TextUtils;
import android.util.Log;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class FileUtils {
public static final boolean IS_USING_PROTECTED_STORAGE = Build.VERSION.SDK_INT >= Build.VERSION_CODES.N;
/**
* Delete a file or a directory and its children.
*
* @param file The directory to delete.
* @throws IOException Exception when problem occurs during deleting the directory.
*/
public static void delete(File file) throws IOException {
for (File childFile : file.listFiles()) {
if (childFile.isDirectory()) {
delete(childFile);
} else {
if (!childFile.delete()) {
throw new IOException();
}
}
}
if (!file.delete()) {
throw new IOException();
}
}
public static String readLine(File file) {
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
return reader.readLine();
} catch (Throwable throwable) {
return "";
}
}
public static void writeLine(File file, String line) {
try {
file.createNewFile();
} catch (IOException ex) {
}
try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) {
writer.write(line);
writer.flush();
} catch (Throwable throwable) {
Log.e("virjar", "error writing line to file " + file + ": " + throwable.getMessage());
}
}
public static String getPackageName(String dataDir) {
if (TextUtils.isEmpty(dataDir)) {
Log.e("virjar", "getPackageName using empty dataDir");
return "";
}
int lastIndex = dataDir.lastIndexOf("/");
if (lastIndex < 0) {
return dataDir;
}
return dataDir.substring(lastIndex + 1);
}
public static String getDataPathPrefix() {
return IS_USING_PROTECTED_STORAGE ? "/data/user_de/0/" : "/data/data/";
}
}
package top.littlerich.virtuallocation.util;
/**
* MapDistanceUtil
*
* @author binghao.huang
* @date 2020-03-04
*/
public class MapDistanceUtil {
private static double PI = 3.14159265;
public static double A = 6378245.0;
public static double EE = 0.00669342162296594323;
public static void main(String[] args) {
// 116.456298,39.923568
GeoPoint gcj02 = bd09ToGcj02(39.923568, 116.456298);
GeoPoint gps = bd09ToGps84(39.923568, 116.456298);
System.out.println(gcj02);
System.out.println(gps);
// 116.397036,39.917834
GeoPoint bd = gcj02ToBd09(39.917834, 116.397036);
gps = gcj02ToGps84(39.917834, 116.397036);
System.out.println(bd);
System.out.println(gps);
}
/**
* gps84 to gcj02
*
* @param lat 纬度
* @param lon 经度
* @return gcj02坐标
*/
public static GeoPoint gps84ToGcj02(double lat, double lon) {
if (outOfChina(lat, lon)) {
return null;
}
double dLat = transformLat(lon - 105.0, lat - 35.0);
double dLon = transformLon(lon - 105.0, lat - 35.0);
double radLat = lat / 180.0 * PI;
double magic = Math.sin(radLat);
magic = 1 - EE * magic * magic;
double sqrtMagic = Math.sqrt(magic);
dLat = (dLat * 180.0) / ((A * (1 - EE)) / (magic * sqrtMagic) * PI);
dLon = (dLon * 180.0) / (A / sqrtMagic * Math.cos(radLat) * PI);
double mgLat = lat + dLat;
double mgLon = lon + dLon;
return new GeoPoint(mgLat, mgLon);
}
/**
* gps84 to bd09
*
* @param lat 纬度
* @param lon 经度
* @return
*/
public static GeoPoint gps84ToBd09(double lat, double lon) {
GeoPoint gps = gps84ToGcj02(lat, lon);
return gcj02ToBd09(gps.getLat(), gps.getLon());
}
/**
* gcj02 to gps84
*
* @param lat 纬度
* @param lon 经度
* @return
*/
public static GeoPoint gcj02ToGps84(double lat, double lon) {
double[] gps = transform(lat, lon);
double longitude = lon * 2 - gps[1];
double latitude = lat * 2 - gps[0];
return new GeoPoint(latitude, longitude);
}
/**
* gcj02 to bd09
*
* @param lat 纬度
* @param lon 经度
* @return
*/
public static GeoPoint gcj02ToBd09(double lat, double lon) {
double x = lon, y = lat;
double z = Math.sqrt(x * x + y * y) + 0.00002 * Math.sin(y * PI);
double theta = Math.atan2(y, x) + 0.000003 * Math.cos(x * PI);
double bdLon = z * Math.cos(theta) + 0.0065;
double bdLat = z * Math.sin(theta) + 0.006;
return new GeoPoint(bdLat, bdLon);
}
/**
* bd04 to gps84
*
* @param lat 纬度
* @param lon 经度
* @return
*/
public static GeoPoint bd09ToGps84(double lat, double lon) {
GeoPoint gcj = bd09ToGcj02(lat, lon);
return gcj02ToGps84(gcj.getLat(), gcj.getLon());
}
/**
* bd09 to gcj02
*
* @param lat 纬度
* @param lon 经度
* @return
*/
public static GeoPoint bd09ToGcj02(double lat, double lon) {
double x = lon - 0.0065, y = lat - 0.006;
double z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * Math.PI);
double theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * Math.PI);
double tempLng = z * Math.cos(theta);
double tempLat = z * Math.sin(theta);
return new GeoPoint(tempLat, tempLng);
}
/**
* 计算两点之间距离
*
* @param lng1
* @param lat1
* @param lng2
* @param lat2
* @return
*/
public static long getDistance(double lng1, double lat1, double lng2, double lat2) {
double RAD = Math.PI / 180.0;
double radLat1 = lat1 * RAD;
double radLat2 = lat2 * RAD;
double a = radLat1 - radLat2;
double b = (lng1 - lng2) * RAD;
double s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) +
Math.cos(radLat1) * Math.cos(radLat2) * Math.pow(Math.sin(b / 2), 2)));
s = s * 6378137;
return Math.round(s * 10000) / 10000;
}
public static double[] transform(double lat, double lon) {
double dLat = transformLat(lon - 105.0, lat - 35.0);
double dLon = transformLon(lon - 105.0, lat - 35.0);
double radLat = lat / 180.0 * PI;
double magic = Math.sin(radLat);
magic = 1 - EE * magic * magic;
double sqrtMagic = Math.sqrt(magic);
dLat = (dLat * 180.0) / ((A * (1 - EE)) / (magic * sqrtMagic) * PI);
dLon = (dLon * 180.0) / (A / sqrtMagic * Math.cos(radLat) * PI);
double mgLat = lat + dLat;
double mgLon = lon + dLon;
return new double[]{mgLat, mgLon};
}
public static double transformLat(double x, double y) {
double ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y
+ 0.2 * Math.sqrt(Math.abs(x));
ret += (20.0 * Math.sin(6.0 * x * PI) + 20.0 * Math.sin(2.0 * x * PI)) * 2.0 / 3.0;
ret += (20.0 * Math.sin(y * PI) + 40.0 * Math.sin(y / 3.0 * PI)) * 2.0 / 3.0;
ret += (160.0 * Math.sin(y / 12.0 * PI) + 320 * Math.sin(y * PI / 30.0)) * 2.0 / 3.0;
return ret;
}
public static double transformLon(double x, double y) {
double ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1
* Math.sqrt(Math.abs(x));
ret += (20.0 * Math.sin(6.0 * x * PI) + 20.0 * Math.sin(2.0 * x * PI)) * 2.0 / 3.0;
ret += (20.0 * Math.sin(x * PI) + 40.0 * Math.sin(x / 3.0 * PI)) * 2.0 / 3.0;
ret += (150.0 * Math.sin(x / 12.0 * PI) + 300.0 * Math.sin(x / 30.0
* PI)) * 2.0 / 3.0;
return ret;
}
/**
* is or not outOfChina
*
* @param lat
* @param lon
* @return
*/
public static boolean outOfChina(double lat, double lon) {
if (lon < 72.004 || lon > 137.8347) {
return true;
}
if (lat < 0.8293 || lat > 55.8271) {
return true;
}
return false;
}
public static class GeoPoint {
private double lat;
private double lon;
public GeoPoint(double lat, double lon) {
this.lat = lat;
this.lon = lon;
}
public double getLat() {
return lat;
}
public double getLon() {
return lon;
}
}
}
/*
* Copyright (c) 2019 The sky 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
*
* http://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.
*/
package top.littlerich.virtuallocation.util;
import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Process;
/**
* Created by sky on 2019/4/8.
*/
public class PermissionUtil {
private PermissionUtil() {
}
public static int checkPermission(Context context, String permission) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
// 请求权限
return context.checkPermission(permission, Process.myPid(), Process.myUid());
}
return PackageManager.PERMISSION_GRANTED;
}
public static void requestPermissions(Activity activity, String[] permissions, int requestCode) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
// 请求权限
activity.requestPermissions(permissions, requestCode);
}
}
}
package top.littlerich.virtuallocation.util;
import java.util.ArrayList;
import java.util.List;
/**
* Created by xuqingfu on 2017/4/17.
*/
public class XposedUtil {
private static List<String> pkgs = new ArrayList<>();
static {
pkgs.add("com.tencent.mm");
pkgs.add("com.tencent.mobileqq");
pkgs.add("com.alibaba.android.rimet");
}
public static void hookAndChange(ClassLoader classLoader){
}
public static boolean isNeedHook(String pkgName){
return pkgs.contains(pkgName);
}
}
package top.littlerich.virtuallocation.view;
import android.view.View;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
/**
* Created by xuqingfu on 2017/5/2.
*/
public class CircleWaveView extends View {
private float mWidth;
private float mHeight;
private float centerX; // 圆心X
private float centerY; // 圆心Y
private float floatRadius; // 变化的半径
private float maxRadius = -1; // 圆半径
private volatile boolean started = false;
private Paint mLinePaint;
private Paint mSolidPaint;
private int waveColor = Color.LTGRAY; // Color.argb(0, 0, 0, 0); //颜色
private int waveInterval = 100; // 圆环的宽度
private boolean centerAlign = true;// 居中
private float bottomMargin = 0;// 底部margin
private boolean fillCircle = true;// 是否填充成实心圆环
public CircleWaveView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CircleWaveView(Context context) {
this(context, null, 0);
}
public CircleWaveView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initView();
}
private void initView() {
mLinePaint = new Paint();
mSolidPaint = new Paint();
}
private void init() {
mWidth = getWidth();
mHeight = getHeight();
mLinePaint.setAntiAlias(true);
mLinePaint.setStrokeWidth(1.0F);
mLinePaint.setStyle(Paint.Style.STROKE);
mLinePaint.setColor(waveColor);
if (fillCircle) {
mSolidPaint.setStyle(Paint.Style.STROKE);
mSolidPaint.setStrokeWidth(waveInterval);
// 设置背景色的颜色
mSolidPaint.setColor(Color.parseColor("#b37400"));
}
centerX = mWidth / 2.0F;
if (centerAlign) {
centerY = (mHeight / 2.0F);
} else {
centerY = mHeight - bottomMargin;
}
if (mWidth >= mHeight) {
maxRadius = mHeight / 2.0F;
} else {
maxRadius = mWidth / 2.0F;
}
floatRadius = (maxRadius % waveInterval);
start();
}
public void start() {
if (!started) {
started = true;
new Thread(thread).start();
}
}
public void stop() {
// Thread.interrupted();
started = true;
}
public void onDetachedFromWindow() {
super.onDetachedFromWindow();
stop();
}
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (maxRadius <= 0.0F) {
return;
}
float radius = floatRadius % waveInterval;
while (true) {
int alpha = (int) (255.0F * (1.0F - radius / maxRadius));
if (alpha <= 0) {
break;
}
// 设置背景色
if (fillCircle) {
mSolidPaint.setAlpha(alpha >> 2);
canvas.drawCircle(centerX, centerY, radius - waveInterval / 2,
mSolidPaint);
}
mLinePaint.setAlpha(alpha);
canvas.drawCircle(centerX, centerY, radius, mLinePaint);
radius += waveInterval;
}
}
public void onWindowFocusChanged(boolean hasWindowFocus) {
super.onWindowFocusChanged(hasWindowFocus);
if (hasWindowFocus) {
init();
} else {
stop();
}
}
//在外面定义一个方法把started设置为true就可以暂停了
private Runnable thread = new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
while (started) {
floatRadius = 4.0F + floatRadius;
if (floatRadius > maxRadius) {
floatRadius = (maxRadius % waveInterval);
postInvalidate();
}
postInvalidate();
try {
Thread.sleep(50L);
} catch (InterruptedException localInterruptedException) {
localInterruptedException.printStackTrace();
}
}
}
};
public void setMaxRadius(float maxRadius) {
this.maxRadius = maxRadius;
}
public void setWaveColor(int waveColor) {
this.waveColor = waveColor;
}
public void setWaveInterval(int waveInterval) {
this.waveInterval = waveInterval;
}
public void setCenterAlign(boolean centerAlign) {
this.centerAlign = centerAlign;
}
}
\ No newline at end of file
package top.littlerich.virtuallocation.view;
import android.content.Context;
import android.widget.TextView;
import com.virjar.ratel.virtuallocation.R;
import top.littlerich.virtuallocation.base.BaseDialog;
/**
* Created by xuqingfu on 2017/4/15.
*/
public class CustomProgressDialog extends BaseDialog {
private TextView tvMsg;
public CustomProgressDialog(Context context) {
super(context);
}
@Override
protected int getContentViewId() {
return R.layout.dialog_customprogress;
}
@Override
protected void InitView() {
tvMsg = (TextView) mView.findViewById(R.id.id_tv_loadingmsg);
}
@Override
protected void IniListener() {
// TODO Auto-generated method stub
}
@Override
protected void InitData() {
}
public void setMessage(String strMessage) {
if (tvMsg != null) {
tvMsg.setText(strMessage);
}
}
}
package top.littlerich.virtuallocation.view;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.text.TextUtils.TruncateAt;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.virjar.ratel.virtuallocation.R;
/**
* 自定义Actionbar
*/
public class TopBanner extends RelativeLayout {
// private static int LEFT_BTN_ID = 1;
// private static int TITLE_ID = 2;
// private static int RIGHT_BTN_ID = 3;
private ImageView leftButton;
private ImageView rightButton;
private TextView title;
private LinearLayout leftLayout;
private LinearLayout rightLayout;
private OnTopBannerListener listener;
@SuppressWarnings("deprecation")
public TopBanner(Context context, AttributeSet attrs) {
super(context, attrs);
String leftButtonText;
float leftButtonTextSize;
Drawable leftButtonBackground;
int leftButtonTextColor;
boolean leftButtonVisiable;
String rightButtonText;
float rightButtonTextSize;
Drawable rightButtonBackground;
int rightButtonTextColor;
boolean rightButtonVisiable;
String titleText;
float titleTextSize;
int titleTextColor;
float rightButtonHeight;
float rightButtonWidth;
float leftButtonHeight;
float leftButtonWidth;
LayoutParams leftButtonParams;
LayoutParams rightButtonParams;
LayoutParams titleButtonParams;
LayoutParams leftParams;
LayoutParams rightParams;
// 获取属性
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.topBanner);
leftButtonText = typedArray.getString(R.styleable.topBanner_leftButtonText);
leftButtonTextSize = typedArray.getDimension(R.styleable.topBanner_leftButtonTextSize, 10);
leftButtonBackground = typedArray.getDrawable(R.styleable.topBanner_leftButtonBackground);
leftButtonTextColor = typedArray.getColor(R.styleable.topBanner_leftButtonTextColor, Color.BLACK);
leftButtonVisiable = typedArray.getBoolean(R.styleable.topBanner_leftButtonVisiable, true);
rightButtonText = typedArray.getString(R.styleable.topBanner_rightButtonText);
rightButtonTextSize = typedArray.getDimension(R.styleable.topBanner_rightButtonTextSize, 10);
rightButtonBackground = typedArray.getDrawable(R.styleable.topBanner_rightButtonBackground);
rightButtonTextColor = typedArray.getColor(R.styleable.topBanner_rightButtonTextColor, Color.BLACK);
rightButtonVisiable = typedArray.getBoolean(R.styleable.topBanner_rightButtonVisiable, true);
titleText = typedArray.getString(R.styleable.topBanner_titleText);
titleTextSize = typedArray.getDimension(R.styleable.topBanner_titleTextSize, 20);
titleTextColor = typedArray.getColor(R.styleable.topBanner_titleTextColors, Color.WHITE);
rightButtonHeight = typedArray.getDimension(R.styleable.topBanner_rightButtonHeight, ViewGroup.LayoutParams.WRAP_CONTENT);
rightButtonWidth = typedArray.getDimension(R.styleable.topBanner_rightButtonWidth, ViewGroup.LayoutParams.WRAP_CONTENT);
leftButtonHeight = typedArray.getDimension(R.styleable.topBanner_leftButtonHeight, ViewGroup.LayoutParams.WRAP_CONTENT);
leftButtonWidth = typedArray.getDimension(R.styleable.topBanner_leftButtonWidth, ViewGroup.LayoutParams.WRAP_CONTENT);
// 属性重用
typedArray.recycle();
leftButton = new ImageView(context);
rightButton = new ImageView(context);
title = new TextView(context);
leftLayout = new LinearLayout(context);
rightLayout = new LinearLayout(context);
// leftLayout.setPadding(30, 30, 30, 30);
// rightLayout.setPadding(30, 30, 30, 30);
leftLayout.setBackgroundColor(0x2723bf);
rightLayout.setBackgroundColor(0x2723bf);
leftParams = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams
.WRAP_CONTENT);
rightParams = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams
.WRAP_CONTENT);
leftButtonParams = new LayoutParams((int) leftButtonWidth, (int) leftButtonHeight);
rightButtonParams = new LayoutParams((int) rightButtonWidth, (int) rightButtonHeight);
titleButtonParams = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
leftParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT, RelativeLayout.TRUE);
leftParams.addRule(RelativeLayout.CENTER_VERTICAL, RelativeLayout.TRUE);// 上下居中
// lxh
leftParams.setMargins(40, 0, 0, 0);// 左上右下
// leftButton.setPadding(40, 10, 10, 10);
leftButton.setPaddingRelative(40, 10, 10, 10);
// leftButtonParams.addRule(RelativeLayout.CENTER_VERTICAL,
// RelativeLayout.TRUE);
rightParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT, RelativeLayout.TRUE);
rightParams.addRule(RelativeLayout.CENTER_VERTICAL, RelativeLayout.TRUE);
rightParams.setMargins(0, 0, 40, 0);// 左上右下
rightButton.setPaddingRelative(10, 10, 40, 10);
// rightButtonParams.addRule(RelativeLayout.CENTER_VERTICAL,
// RelativeLayout.TRUE);
titleButtonParams.addRule(RelativeLayout.CENTER_IN_PARENT, RelativeLayout.TRUE);
// titleButtonParams.addRule(RelativeLayout.LEFT_OF, RIGHT_BTN_ID);
// titleButtonParams.addRule(RelativeLayout.RIGHT_OF, LEFT_BTN_ID);
leftLayout.addView(leftButton, leftButtonParams);
rightLayout.addView(rightButton, rightButtonParams);
addView(leftLayout, leftParams);
addView(rightLayout, rightParams);
addView(title, titleButtonParams);
// 设置对应的属性值
// leftButton.setGravity(Gravity.CENTER);
// leftButton.setText(leftButtonText);
// leftButton.setTextColor(leftButtonTextColor);
// leftButton.setTextSize(TypedValue.COMPLEX_UNIT_DIP, leftButtonTextSize);
leftButton.setBackgroundDrawable(leftButtonBackground);
setLeftButtonVisibility(leftButtonVisiable);
// rightButton.setGravity(Gravity.CENTER);
// rightButton.setText(rightButtonText);
// rightButton.setTextColor(rightButtonTextColor);
// rightButton.setTextSize(TypedValue.COMPLEX_UNIT_DIP, rightButtonTextSize);
rightButton.setBackgroundDrawable(rightButtonBackground);
setRightButtonVisibility(rightButtonVisiable);
title.setText(titleText);
title.setTextSize(TypedValue.COMPLEX_UNIT_DIP, titleTextSize);
title.setTextColor(titleTextColor);
title.setEllipsize(TruncateAt.MARQUEE);
title.setGravity(Gravity.CENTER);
title.setSingleLine(true);
leftLayout.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (null != listener) {
listener.leftClick(v);
}
}
});
rightLayout.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (null != listener) {
listener.rightClick(v);
}
}
});
}
public void setTopBannerListener(OnTopBannerListener listener) {
this.listener = listener;
}
private void setLeftButtonVisibility(Boolean isVisibility) {
leftButton.setVisibility(isVisibility ? View.VISIBLE : View.GONE);
}
private void setRightButtonVisibility(Boolean isVisibility) {
rightButton.setVisibility(isVisibility ? View.VISIBLE : View.GONE);
}
public String getTitleText() {
return title.getText().toString().trim();
}
public void setTitleText(String titleText) {
title.setText(titleText);
}
public ImageView getLeftButton() {
return leftButton;
}
public ImageView getRightButton() {
return rightButton;
}
public LinearLayout getLeftLayout() {
return leftLayout;
}
public LinearLayout getRightLayout() {
return rightLayout;
}
public interface OnTopBannerListener {
void leftClick(View v);
void rightClick(View v);
}
}
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<rotate
android:fromDegrees="0"
android:toDegrees="359"
android:duration="800"
android:repeatCount="-1"
android:pivotX="50%"
android:pivotY="50%" />
</set>
\ No newline at end of file
<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="oval"
android:useLevel="false" >
<solid android:color="@android:color/background_dark" />
<padding
android:left="1dp"
android:top="1dp"
android:right="1dp"
android:bottom="1dp" />
<stroke
android:width="5dp"
android:color="@android:color/darker_gray" />
<size android:width="10dp"
android:height="10dp" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<gradient
android:angle="90"
android:endColor="#00fcfbfb"
android:startColor="#88a3a2a0"/>
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<corners android:radius="5dp"/>
<solid android:color="#fff"/>
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:pivotX="50%" android:pivotY="50%"
android:fromDegrees="0" android:toDegrees="360">
<shape
android:shape="ring"
android:innerRadiusRatio="3"
android:thicknessRatio="30"
android:useLevel="false">
<gradient
android:type="sweep"
android:useLevel="false"
android:startColor="@color/colorAccent"
android:centerColor="@color/colorTopBanner"
android:centerY="0.50"
android:endColor="@color/colorPrimaryDark" />
</shape>
</rotate>
\ 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"
android:useLevel="false" >
<solid android:color="#fff" />
<padding
android:left="1dp"
android:top="1dp"
android:right="1dp"
android:bottom="1dp" />
<stroke
android:width="1.5dp"
android:color="@android:color/darker_gray" />
<size android:width="12dp"
android:height="12dp" />
</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"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:custom="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#f6f6f6"
android:orientation="vertical"
tools:context="top.littlerich.virtuallocation.activity.AboutActivity">
<top.littlerich.virtuallocation.view.TopBanner
android:id="@+id/topbanner"
style="@style/TopBannerBaseStyle"
android:layout_alignParentTop="true"
custom:leftButtonBackground="@mipmap/ic_reback"
custom:leftButtonHeight="20dp"
custom:leftButtonVisiable="true"
custom:leftButtonWidth="25dp"
custom:titleText="关于"
android:background="#fff"
custom:titleTextColors="#000"
/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="#fff"
android:paddingTop="30dp"
android:layout_marginTop="1dp"
>
<ImageView
android:layout_width="70dp"
android:layout_height="70dp"
android:layout_gravity="center_horizontal"
android:src="@mipmap/logo_launcher"
android:layout_margin="10dp"
/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/app_introduce"
android:padding="15dp"
android:lineSpacingMultiplier="1.2"
/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginTop="20dp"
android:background="#fff"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="微博服务号"
android:padding="15dp"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="virjar"
android:padding="15dp"
android:gravity="end"
/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginTop="2dp"
android:background="#fff"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="作者网址"
android:padding="15dp"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="http://github.com/virjar/"
android:padding="15dp"
android:gravity="end"
/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginTop="20dp"
android:background="#fff"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="使用手册"
android:padding="15dp"
android:drawableRight="@mipmap/ic_right"
/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginTop="20dp"
android:background="#fff"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="开源许可证"
android:padding="15dp"
android:drawableRight="@mipmap/ic_right"
/>
</LinearLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="bottom|center_horizontal"
android:layout_weight="1"
android:text="@string/app_version_copyright"
android:textSize="12sp"
android:paddingBottom="20dp"
android:lineSpacingMultiplier="1.5"
/>
</LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:custom="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="top.littlerich.virtuallocation.activity.AppsActivity">
<top.littlerich.virtuallocation.view.TopBanner
android:id="@+id/topbanner"
style="@style/TopBannerBaseStyle"
android:layout_alignParentTop="true"
custom:leftButtonBackground="@mipmap/ic_reback"
custom:rightButtonBackground="@mipmap/ic_filter"
custom:leftButtonHeight="20dp"
custom:leftButtonVisiable="true"
custom:leftButtonWidth="25dp"
custom:titleTextColors="#c1030303"
custom:titleText="添加Hook程序"/>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.RecyclerView
android:id="@+id/my_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical"/>
<ProgressBar
android:id="@+id/pb_progressbar"
android:layout_width="65dp"
android:layout_height="65dp"
android:layout_centerInParent="true"
android:indeterminateDrawable="@drawable/bg_progressbar"/>
/>
</RelativeLayout>
</LinearLayout>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:custom="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.baidu.mapapi.map.MapView
android:id="@+id/bmapView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="true"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
>
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
custom:cardElevation="8dp"
>
<top.littlerich.virtuallocation.view.TopBanner
android:id="@+id/topbanner"
style="@style/TopBannerBaseStyle"
android:layout_alignParentTop="true"
custom:leftButtonBackground="@mipmap/ic_expand"
custom:leftButtonHeight="15dp"
custom:leftButtonVisiable="true"
custom:leftButtonWidth="20dp"
custom:rightButtonBackground="@mipmap/ic_topbar_search"
custom:titleText="@string/app_name"
custom:titleTextColors="#c1030303"/>
</android.support.v7.widget.CardView>
<TextView
android:id="@+id/tv_location"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="15dp"
android:background="@drawable/bg_notice"
android:drawableLeft="@mipmap/ic_virtual_addr"
android:drawablePadding="7dp"
android:gravity="center_vertical"
android:paddingBottom="10dp"
android:paddingLeft="15dp"
android:paddingRight="15dp"
android:paddingTop="10dp"
android:text="伪造地址"
android:textColor="#ff665e"
/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:background="@drawable/bg_botton_shadow"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingBottom="25dp"
android:paddingLeft="20dp"
android:paddingRight="20dp"
>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginTop="13dp"
>
<ImageView
android:id="@+id/iv_location"
android:layout_width="50dp"
android:layout_height="50dp"
android:background="@drawable/bg_with_round"
android:padding="10dp"
android:src="@mipmap/ic_current_location"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="定位"
android:layout_margin="4dp"
android:layout_gravity="center_horizontal"
android:textSize="13sp"
android:textColor="#423f24"
/>
</LinearLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
>
<Button
android:id="@+id/bt_Ok"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_gravity="center"
android:layout_margin="10dp"
android:background="@drawable/bg_begin_location"
android:text="立即穿越"
android:textColor="#fbd12d"
/>
</RelativeLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginTop="13dp"
>
<ImageView
android:id="@+id/iv_stop_location"
android:layout_width="50dp"
android:layout_height="50dp"
android:background="@drawable/bg_with_round"
android:clickable="true"
android:padding="10dp"
android:src="@mipmap/ic_stop_location"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="重置"
android:layout_margin="4dp"
android:layout_gravity="center_horizontal"
android:textSize="13sp"
android:textColor="#423f24"
/>
</LinearLayout>
</LinearLayout>
<top.littlerich.virtuallocation.view.CircleWaveView
android:layout_width="250dp"
android:layout_height="250dp"
android:layout_gravity="center"
android:layout_margin="15dp"
/>
</FrameLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:custom="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="top.littlerich.virtuallocation.activity.PreciseLocationActivity">
<top.littlerich.virtuallocation.view.TopBanner
android:id="@+id/topbanner"
style="@style/TopBannerBaseStyle"
android:layout_alignParentTop="true"
custom:leftButtonBackground="@mipmap/ic_reback"
custom:leftButtonHeight="20dp"
custom:leftButtonVisiable="true"
custom:leftButtonWidth="25dp"
custom:titleText="精确定位"
custom:titleTextColors="#c1030303"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_margin="20dp"
android:orientation="vertical"
android:focusable="true"
android:focusableInTouchMode="true"
>
<android.support.design.widget.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:layout_marginBottom="8dp"
android:layout_marginTop="8dp"
>
<EditText
android:id="@+id/et_latitude"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:hint="请输入精确经度值"
android:inputType="numberDecimal"
/>
</android.support.design.widget.TextInputLayout>
<android.support.design.widget.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:layout_marginBottom="8dp"
android:layout_marginTop="8dp"
>
<EditText
android:id="@+id/et_longitude"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:hint="请输入精确维度值"
android:inputType="numberDecimal"
/>
</android.support.design.widget.TextInputLayout>
<android.support.v7.widget.AppCompatButton
android:id="@+id/btn_precise_location"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:layout_marginBottom="24dp"
android:padding="15dp"
android:background="#36cace"
android:textColor="#fff"
android:text="精确定位"/>
<ProgressBar
android:id="@+id/pb_locating"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_marginTop="24dp"
android:layout_marginBottom="24dp"
android:padding="15dp"
android:background="@drawable/bg_with_round"
android:textColor="#fff"
android:layout_gravity="center"
android:clickable="true"
android:visibility="gone"/>
</LinearLayout>
<TextView
android:id="@+id/tv_tip"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="※ 已穿越到指定地点,快打开需要虚拟定位的APP试试!"
android:layout_margin="20dp"
android:layout_below="@id/topbanner"
android:lineSpacingMultiplier="1.2"
android:textColor="@color/colorAccent"
android:visibility="gone"
/>
</RelativeLayout>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="horizontal" >
<ProgressBar
style="?android:attr/progressBarStyleSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/id_tv_loadingmsg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:text="loading..."
android:textColor="@android:color/white" />
</LinearLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#cccaca"
/>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="70dp">
<ImageView
android:id="@+id/iv_app_icon"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:layout_marginLeft="12dp"
android:src="@mipmap/ic_launcher"
/>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="12dp"
android:layout_marginRight="12dp"
android:layout_toRightOf="@id/iv_app_icon"
android:orientation="vertical"
>
<TextView
android:id="@+id/tv_app_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:text="@string/app_name"
android:textSize="18sp"
/>
<TextView
android:id="@+id/tv_app_pkg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:singleLine="true"
android:text="@string/item_application_name"
/>
</LinearLayout>
<CheckBox
android:id="@+id/cb_app_select"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginRight="20dp"
/>
</RelativeLayout>
</LinearLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
<TextView
android:id="@+id/tv_add_app"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="添加程序"
android:drawableLeft="@mipmap/ic_drawer_add"
android:drawablePadding="10dp"
android:gravity="center_vertical"
android:layout_margin="10dp"
/>
<TextView
android:id="@+id/tv_precise"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="精确定位"
android:drawableLeft="@mipmap/ic_drawer_add"
android:drawablePadding="10dp"
android:gravity="center_vertical"
android:layout_margin="10dp"
/>
<TextView
android:id="@+id/tv_about_me"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="关于"
android:drawableLeft="@mipmap/ic_drawer_me"
android:drawablePadding="10dp"
android:gravity="center_vertical"
android:layout_margin="10dp"
/>
</LinearLayout>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#eeeeee"
tools:context=".activity.MainActivity">
<android.support.v4.widget.DrawerLayout
android:id="@+id/dl_left"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<include layout="@layout/activity_main"/>
</FrameLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="start"
android:background="#fff">
<include layout="@layout/layout_drawer"/>
</LinearLayout>
</android.support.v4.widget.DrawerLayout>
</FrameLayout>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:id="@+id/action_my"
android:orderInCategory="80"
android:title="我的位置"/>
<item
android:id="@+id/action_about"
android:orderInCategory="90"
android:title="关于"/>
</menu>
\ 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
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="topBanner">
<attr name="leftButtonText" format="string"/>
<attr name="leftButtonTextSize" format="dimension"/>
<attr name="leftButtonBackground" format="reference|color"/>
<attr name="leftButtonTextColor" format="color"/>
<attr name="leftButtonVisiable" format="boolean"/>
<attr name="titleText" format="string"/>
<attr name="titleTextSize" format="dimension"/>
<attr name="titleTextColors" format="color"/>
<attr name="rightButtonText" format="string"/>
<attr name="rightButtonTextSize" format="dimension"/>
<attr name="rightButtonWidth" format="dimension"/>
<attr name="rightButtonHeight" format="dimension"/>
<attr name="leftButtonWidth" format="dimension"/>
<attr name="leftButtonHeight" format="dimension"/>
<attr name="rightButtonBackground" format="reference|color"/>
<attr name="rightButtonTextColor" format="color"/>
<attr name="rightButtonVisiable" format="boolean"/>
</declare-styleable>
</resources>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#3F51B5</color>
<color name="colorPrimaryDark">#303F9F</color>
<color name="colorAccent">#FF4081</color>
<color name="colorTopBanner">#42ABC1</color>
</resources>
<resources>
<string name="app_name">筋斗云</string>
<string name="app_introduce"> 筋斗云是一款虚拟定位软件,让你随心所欲的改变手机地理位置!本项目改造自:https://github.com/littleRich/VirtualLocation </string>
<string name="app_version_copyright">当前版本:1.0.0(build 20200827) \n@2017 ratel.virjar.com All right reserved</string>
<string name="item_application_name">应用程序名</string>
</resources>
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
<!-- dialog不透明样式 -->
<style name="clashDialog" parent="@android:Theme.Dialog">
<item name="android:windowFrame">@null</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:windowIsFloating">true</item>
<item name="android:windowFullscreen">true</item>
<item name="android:windowContentOverlay">@null</item>
<item name="android:backgroundDimEnabled">true</item>
</style>
<!-- TopBar属性-->
<style name="TopBannerBaseStyle">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">48dp</item>
<item name="android:background">#fff</item>
</style>
</resources>
/*
* Copyright (c) 2019 The sky 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
*
* http://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.
*/
buildscript {
repositories {
maven {
name "aliyunmaven"
url "https://maven.aliyun.com/repository/public"
}
maven {
name "aliyunGoogle"
url "https://maven.aliyun.com/repository/google"
}
}
dependencies {
classpath 'com.android.tools.build:gradle:3.5.0'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
google()
maven {
name "aliyunmaven"
url "https://maven.aliyun.com/repository/public"
}
maven {
name "aliyunGoogle"
url "https://maven.aliyun.com/repository/google"
}
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
# 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=-Xmx2048m
# 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=false
# Automatically convert third-party libraries to use AndroidX
android.enableJetifier=false
\ No newline at end of file
#Tue Aug 25 16:07:37 CST 2020
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip
#!/usr/bin/env sh
##############################################################################
##
## 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=""
# 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, switch paths to Windows format before running java
if $cygwin ; 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=$((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"
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi
exec "$JAVACMD" "$@"
@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 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=
@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 init
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 init
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
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
: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 %CMD_LINE_ARGS%
: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
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in D:\DevSoft\Android\AndroidSDK/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# 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
-keep class com.baidu.** {*;}
-keep class vi.com.** {*;}
-dontwarn com.baidu.**
include ':app'
rootProject.name = "RatelVirtualLocation"
\ No newline at end of file
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