Commit eecc09c6 by maiqh

init

parents
*.iml
.gradle
/local.properties
/.idea/caches
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
.DS_Store
/build
/captures
.externalNativeBuild
.cxx
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<codeStyleSettings language="XML">
<indentOptions>
<option name="CONTINUATION_INDENT_SIZE" value="4" />
</indentOptions>
<arrangement>
<rules>
<section>
<rule>
<match>
<AND>
<NAME>xmlns:android</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>xmlns:.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:id</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:name</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>name</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>style</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>ANDROID_ATTRIBUTE_ORDER</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>.*</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
</rules>
</arrangement>
</codeStyleSettings>
</code_scheme>
</component>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleMigrationSettings" migrationVersion="1" />
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="testRunner" value="PLATFORM" />
<option name="distributionType" value="DEFAULT_WRAPPED" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleJvm" value="1.8" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" />
<option value="$PROJECT_DIR$/imlinkclient" />
</set>
</option>
<option name="resolveModulePerSourceSet" value="false" />
</GradleProjectSettings>
</option>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RemoteRepositoriesConfiguration">
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Maven Central repository" />
<option name="url" value="https://repo1.maven.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="jboss.community" />
<option name="name" value="JBoss Community repository" />
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
</remote-repository>
<remote-repository>
<option name="id" value="BintrayJCenter" />
<option name="name" value="BintrayJCenter" />
<option name="url" value="https://jcenter.bintray.com/" />
</remote-repository>
<remote-repository>
<option name="id" value="Google" />
<option name="name" value="Google" />
<option name="url" value="https://dl.google.com/dl/android/maven2/" />
</remote-repository>
<remote-repository>
<option name="id" value="D:\SDK\extras\m2repository" />
<option name="name" value="D:\SDK\extras\m2repository" />
<option name="url" value="file:/D:/SDK/extras/m2repository" />
</remote-repository>
<remote-repository>
<option name="id" value="D:\SDK\extras\google\m2repository" />
<option name="name" value="D:\SDK\extras\google\m2repository" />
<option name="url" value="file:/D:/SDK/extras/google/m2repository" />
</remote-repository>
<remote-repository>
<option name="id" value="D:\SDK\extras\android\m2repository" />
<option name="name" value="D:\SDK\extras\android\m2repository" />
<option name="url" value="file:/D:/SDK/extras/android/m2repository/" />
</remote-repository>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">
<option name="id" value="Android" />
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RunConfigurationProducerService">
<option name="ignoredProducers">
<set>
<option value="org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer" />
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer" />
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer" />
</set>
</option>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
</component>
</project>
\ No newline at end of file
/build
\ No newline at end of file
apply plugin: 'com.android.application'
android {
compileSdkVersion 22
defaultConfig {
applicationId "com.mxnavi.imlinkserver"
minSdkVersion 21
targetSdkVersion 22
versionCode 2
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"])
implementation files('libs\\android.policy.jar')
}
\ No newline at end of file
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
\ No newline at end of file
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.imlinkdemo">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme" >
<meta-data
android:name="cneeds_launcher_item_view"
android:value="com.view.ItemView" />
<meta-data
android:name="cneeds_launcher_divider_view"
android:value="com.view.ItemView" />
<meta-data
android:name="cneeds_launcher_item_view_order_id"
android:resource="@integer/launcher_index" />
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<service
android:name="com.mxnavi.applauncher.MLinkService"
android:exported="true">
<intent-filter>
<action android:name="com.mxnavi.mlink.ACTION_BIND_MLINK_SERVICE" />
</intent-filter>
</service>
</application>
</manifest>
\ No newline at end of file
package com.mxnavi.applauncher;
import com.mxnavi.applauncher.IMlinkServiceClient;
interface IMlinkService {
// 注册回调
oneway void registerMlinkServiceClient(in IMlinkServiceClient client);
// 反注册回调
oneway void unregisterMlinkServiceClient(in IMlinkServiceClient client);
// BT连接状态
boolean onBtConnectionStatus(boolean isConnected, String mac);
// isConnected true 连接, false 断开
// macmac地址
// 接收蓝牙数据
boolean onReceivedBtData(in byte[] data);
// WIFI连接状态
boolean onWifiConnectionStatus(boolean isConnected, String mac);
// isConnected true 连接, false 断开
// macmac地址
}
package com.mxnavi.applauncher;
interface IMlinkServiceClient {
// 回调接口
oneway void onHUCommand(int cmd, in Bundle bundle);
// 1. 发送蓝牙数据:
// cmd 328202
// Bundle
// 数据: key "btData" 类型:byte[]
// 2. WIFI配置信息:
// cmd 328203
// Bundle
// SSID key "ssid" 类型:String
// PASS key "pass" 类型:String
// Security Type key "securityType",类型:byte
// Channel key " channel " 类型:byte
}
package com.example.imlinkdemo;
import android.app.Activity;
import android.os.Bundle;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
package com.mxnavi.applauncher;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import java.util.Arrays;
public class MLinkService extends Service {
private static final String TAG = "MLinkService";
private IMlinkServiceClient mClient;
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
IMlinkService.Stub mBinder = new IMlinkService.Stub() {
@Override
public void registerMlinkServiceClient(IMlinkServiceClient client) throws RemoteException {
mClient = client;
}
@Override
public void unregisterMlinkServiceClient(IMlinkServiceClient client) throws RemoteException {
}
@Override
public boolean onBtConnectionStatus(boolean isConnected, String mac) throws RemoteException {
return false;
}
@Override
public boolean onReceivedBtData(byte[] data) throws RemoteException {
Log.d(TAG, "onReceiveBtData : "+Arrays.toString(data));
return false;
}
@Override
public boolean onWifiConnectionStatus(boolean isConnected, String mac) throws RemoteException {
return false;
}
};
}
package com.view;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.util.AttributeSet;
import android.widget.RelativeLayout;
/**
* author: jack
* date: 2018/8/30 18:12
* desc:Launcher界面基类
*/
public abstract class BaseLauncherView extends RelativeLayout {
private static final String TAG = "BaseLauncherView";
//UI state
public static final int STATE_NO_CONNECT = 0;
public static final int STATE_CONNECT = 1;
public static final int STATE_CALL = 2;
protected final Context mContext;
protected Context mReadResContext;
//view
protected RelativeLayout mRlRoot;
public BaseLauncherView(Context context) {
this(context, null);
}
public BaseLauncherView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public BaseLauncherView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.mContext = context;
try {
mReadResContext = mContext.createPackageContext(Constants.PACKAGE_NAME, Context.CONTEXT_IGNORE_SECURITY | Context.CONTEXT_INCLUDE_CODE);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
onInit(context, attrs, defStyleAttr);
}
public abstract void onInit(Context context, AttributeSet attrs, int defStyleAttr);
/**
* 启动App
*/
protected void startupApp() {
Intent targetIntent = getContext().getPackageManager().getLaunchIntentForPackage(Constants.PACKAGE_NAME);
mContext.startActivity(targetIntent);
}
protected void toHome() {
Intent home = new Intent(Intent.ACTION_MAIN);
home.addCategory(Intent.CATEGORY_HOME);
getContext().startActivity(home);
}
}
package com.view;
public class Constants {
//应用包名
public static final String PACKAGE_NAME = "com.mxnavi.applauncher";
}
package com.view;
import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.LinearLayout;
import com.example.imlinkdemo.R;
public class ItemView extends BaseLauncherView{
public ItemView(Context context) {
super(context);
}
@Override
public void onInit(Context context, AttributeSet attrs, int defStyleAttr) {
LayoutInflater.from(context).inflate(R.layout.launcher_view, this);
LinearLayout root = (LinearLayout) findViewById(R.id.ll_root);
root.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
startupApp();
}
});
}
}
<?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"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/btn_hello"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!!"/>
</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:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/ll_root"
android:gravity="center">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="25sp"
android:text="IMLinkServer"/>
</LinearLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#6200EE</color>
<color name="colorPrimaryDark">#3700B3</color>
<color name="colorAccent">#03DAC5</color>
</resources>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<integer name="launcher_index">7</integer>
</resources>
\ No newline at end of file
<resources>
<string name="app_name">IMLinkServer</string>
</resources>
\ No newline at end of file
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="@android:style/Theme.NoTitleBar.Fullscreen">
<item name="android:windowAnimationStyle">@style/Animation</item>
</style>
<style name="MyAppTheme" parent="@android:style/Theme.NoTitleBar.Fullscreen">
</style>
<style name="Animation">
<item name="android:activityOpenEnterAnimation">@null</item>
<item name="android:activityOpenExitAnimation">@null</item>
<item name="android:activityCloseEnterAnimation">@null</item>
<item name="android:activityCloseExitAnimation">@null</item>
<item name="android:taskOpenEnterAnimation">@null</item>
<item name="android:taskOpenExitAnimation">@null</item>
<item name="android:taskCloseEnterAnimation">@null</item>
<item name="android:taskCloseExitAnimation">@null</item>
<item name="android:taskToFrontEnterAnimation">@null</item>
<item name="android:taskToFrontExitAnimation">@null</item>
<item name="android:taskToBackEnterAnimation">@null</item>
<item name="android:taskToBackExitAnimation">@null</item>
</style>
</resources>
\ No newline at end of file
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath "com.android.tools.build:gradle:3.1.2"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
google()
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
\ No newline at end of file
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-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=true
# Automatically convert third-party libraries to use AndroidX
android.enableJetifier=true
\ No newline at end of file
#Thu Jul 30 11:43:29 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
/build
\ No newline at end of file
apply plugin: 'com.android.application'
android {
compileSdkVersion 22
defaultConfig {
applicationId "com.example.imlinkclient"
minSdkVersion 21
targetSdkVersion 22
versionCode 1
versionName "1.0"
}
buildTypes {
debug {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"])
}
\ No newline at end of file
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
-keep public class com.example.imlinkclient.helpr.MLinkServiceHelper
-keepclassmembers class com.example.imlinkclient.helpr.MLinkServiceHelper{
*;
}
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class * extends android.app.backup.BackupAgentHelper
-keep public class * extends android.preference.Preference
-keep public interface com.mxnavi.mlink.serversdk.service.IMlinkService
-keepclassmembers class com.mxnavi.mlink.serversdk.service.IMlinkService{
*;
}
-keep public interface com.mxnavi.mlink.serversdk.service.IMlinkServiceClient
-keepclassmembers class com.mxnavi.mlink.serversdk.service.IMlinkServiceClient{
*;
}
-keep public class com.example.imlinkclient.view.BaseLauncherView
-keep public class com.example.imlinkclient.view.ItemView
-keepclassmembers class com.example.imlinkclient.view.BaseLauncherView{
*;
}
-keepclassmembers class com.example.imlinkclient.view.ItemView{
*;
}
\ No newline at end of file
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.imlinkclient"
android:sharedUserId="android.uid.system"
>
//
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.BLUETOOTH_PRIVILEGED" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
<uses-permission android:name="android.permission.WRITE_SETTINGS"/>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
android:name=".ClientApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme" >
<meta-data
android:name="cneeds_launcher_item_view"
android:value="com.example.imlinkclient.view.ItemView" />
<meta-data
android:name="cneeds_launcher_divider_view"
android:value="com.example.imlinkclient.view.ItemView" />
<meta-data
android:name="cneeds_launcher_item_view_order_id"
android:resource="@integer/launcher_index" />
<activity android:name=".MainClientActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
</application>
</manifest>
\ No newline at end of file
package com.cneeds.settings.bean;
parcelable AccessPoint;
// IWiFiPresenter.aidl
package com.cneeds.settings.bean;
import com.cneeds.settings.bean.AccessPoint;
import com.cneeds.settings.bean.IWiFiView;
interface IWiFiPresenter {
void openWifi();//打开wifi
void closeWifi();//关闭wifi
void connect(in AccessPoint point);
void connectByPW(String password,in AccessPoint point);
void forget(in AccessPoint point);
// void openHotspot(String password);
// void closeHotspot();
// void updateHotspot(String password);
void registerView(in IWiFiView view);
void unRegisterView(in IWiFiView view);
}
// IWiFiView.aidl
package com.cneeds.settings.bean;
import com.cneeds.settings.bean.AccessPoint;
import com.cneeds.settings.bean.IWiFiPresenter;
interface IWiFiView {
void setPresenter(in IWiFiPresenter presenter);
void wifiEnable(int state);
void updateAPList(in List<AccessPoint> list);
void passwordInput();
void connecting();
}
// IDVRPresenter.aidl
package com.cneeds.wifidvr;
interface IDVRLauncherView {
//0.wifi没开 1.未连接 2.连上wifi 3.连上记录仪
void onWifiStatus(int status);
}
// IDVRPresenter.aidl
package com.cneeds.wifidvr;
import com.cneeds.wifidvr.IDVRLauncherView;
interface IDVRPresenter {
void register(in IDVRLauncherView view);
void unRegister(in IDVRLauncherView view);
void openWifi();
}
package com.mxnavi.mlink.serversdk.service;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import android.hardware.usb.UsbAccessory;
import android.content.Intent;
import com.mxnavi.mlink.serversdk.service.IMlinkServiceClient;
interface IMlinkService {
/**
* Check if there is a client connected.
*/
boolean isMlinkClientConnected();
oneway void onUsbAccessoryAcquired(in UsbAccessory accessory);
oneway void onMediaProjectionAcquired(int resultCode, in Intent data);
oneway void registerMlinkServiceClient(in IMlinkServiceClient client);
oneway void unregisterMlinkServiceClient(in IMlinkServiceClient client);
boolean sendMediaInit(int sampleRate, int channelConfig, int sampleFormat);
boolean sendMediaPlay();
boolean sendMediaPause();
boolean sendMediaData(in byte[] buffer);
boolean sendMediaInfo(String source, String song, String artist, String album,in byte[] albumArt,
int duration, int playlistNum, String songId, int mode);
boolean sendNaviTTSInit(int sampleRate, int channelConfig, int sampleFormat);
boolean sendNaviTTSData(in byte[] buffer);
boolean sendNaviTTSEnd();
boolean sendTelAudioInit(int sampleRate, int channelConfig, int sampleFormat);
boolean sendTelAudioData(in byte[] data);
boolean sendTelAudioStop();
boolean sendTelAudioStopp(boolean bStayIn);
boolean sendTelCallStateInfo(String phoneNum, String callerName, int status);
/**
* 通知车机端进入唤醒状态了,需要开始录音
*/
boolean sendMicRecordWakeupStart();
/**
* 通知车机端进入识别状态了,需要开始录音
*/
boolean sendMicRecordRecogStart();
/**
* 发送录音结束命令给车机
*/
boolean sendMicRecordEnd();
boolean sendVRAudioInit(int sampleRate, int channelConfig, int sampleFormat);
boolean sendVRAudioData(in byte[] data);
boolean sendVRAAudioStop();
boolean sendVRAAudioStopp(boolean bStayIn);
boolean sendVRAudioInterrupt();
boolean sendVRModuleStatusMsg(int statusId);
boolean sendNaviNextTurnInfo(int action, int nextTurn, String roadName, int totalDistance, int remainDistance, int time);
boolean sendCarlifeModuleStatus(int moduleId, int statusId);
String getLinkProtocol();
boolean pauseMedia();
boolean resumeMedia();
boolean sendGoToDesktop();
boolean useMobileMic();
boolean sendBluetoothInfo(String name, String address);
boolean onBtConnectionStatus(boolean isConnected, String mac);
boolean onReceivedBtData(in byte[] data);
boolean onWifiConnectionStatus(boolean isConnected, String mac);
// 以下 api 仅供 CRV 车机使用
/**
* 设定context infomation函数,以下时机调用:
* 1. QQMusic, 喜马拉雅开始播放
* 2. Launcher QQMusic,喜马拉雅,语助到前台
* @param id appID 具体参考下表
* lancher_appid = 0x1;
* navi_appid = 0x2;
* radio_appid = 0x3;
* musci_appid = 0x4;
* weather_appid = 0x5;
* setting_appid = 0x6;
* vr_appid = 0x7;
* tencent tv = 0x8;
*/
int setContextInfo(int id);
int appStopped(int id);
}
package com.mxnavi.mlink.serversdk.service;
import android.os.Bundle;
interface IMlinkServiceClient {
oneway void onConnectionStateChanged(boolean isConnected);
oneway void onHUCommand(int cmd, in Bundle bundle);
}
/*
* Copyright (C) 2010 The Android Open Source Project
*
* 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 com.cneeds.settings.bean;
import android.net.NetworkInfo;
import android.net.NetworkInfo.DetailedState;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiConfiguration.KeyMgmt;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Log;
import com.example.imlinkclient.utils.InvokeUtil;
public class AccessPoint implements Parcelable, Comparable<AccessPoint> {
static final String TAG = "Settings.AccessPoint";
/** {@hide} */
public static final int INVALID_NETWORK_ID = -1;
public static final int SECURITY_NONE = 0;
public static final int SECURITY_WEP = 1;
public static final int SECURITY_PSK = 2;
public static final int SECURITY_EAP = 3;
public enum PskType {
UNKNOWN,
WPA,
WPA2,
WPA_WPA2
}
private PskType pskType = PskType.UNKNOWN;
private String ssid;
private String bssid;
private int security;
private int networkId = -1;
boolean wpsAvailable = false;
private int mRssi = Integer.MAX_VALUE;
private long mSeen = 0;
private ScanResult mScanResult;
private WifiConfiguration mConfig;
private WifiInfo mInfo;
private NetworkInfo mNetworkInfo;
public AccessPoint(WifiConfiguration config) {
loadConfig(config);
}
public AccessPoint(ScanResult result) {
loadResult(result);
}
private void loadConfig(WifiConfiguration config) {
synchronized (AccessPoint.class) {
ssid = (config.SSID == null ? "" : removeDoubleQuotes(config.SSID));
bssid = config.BSSID;
security = getSecurity(config);
networkId = config.networkId;
mConfig = config;
}
}
private void loadResult(ScanResult result) {
synchronized (AccessPoint.class) {
ssid = result.SSID;
bssid = result.BSSID;
security = getSecurity(result);
wpsAvailable = security != SECURITY_EAP && result.capabilities.contains("WPS");
if (security == SECURITY_PSK) {
pskType = getPskType(result);
}
mRssi = result.level;
mScanResult = result;
Long seen = InvokeUtil.getDeclaredField(ScanResult.class, "seen", result);
if (seen > mSeen) {
mSeen = seen;
}
}
}
@Override
public int compareTo(AccessPoint other) {
synchronized (AccessPoint.class) {
// Active one goes first.
if (isActive() && !other.isActive()) return -1;
if (!isActive() && other.isActive()) return 1;
// Reachable one goes before unreachable one.
if (mRssi != Integer.MAX_VALUE && other.mRssi == Integer.MAX_VALUE) return -1;
if (mRssi == Integer.MAX_VALUE && other.mRssi != Integer.MAX_VALUE) return 1;
// Configured one goes before unconfigured one.
if (networkId != INVALID_NETWORK_ID
&& other.networkId == INVALID_NETWORK_ID) return -1;
if (networkId == INVALID_NETWORK_ID
&& other.networkId != INVALID_NETWORK_ID) return 1;
// Sort by signal strength.
int difference = WifiManager.compareSignalLevel(other.mRssi, mRssi);
if (difference != 0) {
return difference;
}
// Sort by ssid.
return ssid.compareToIgnoreCase(other.ssid);
}
}
public boolean update(ScanResult result) {
synchronized (AccessPoint.class) {
Long seen = InvokeUtil.getDeclaredField(ScanResult.class, "seen", result);
if (seen > mSeen) {
mSeen = seen;
}
if (ssid.equals(result.SSID) && security == getSecurity(result)) {
if (WifiManager.compareSignalLevel(result.level, mRssi) > 0) {
mRssi = result.level;
}
// This flag only comes from scans, is not easily saved in config
if (security == SECURITY_PSK) {
pskType = getPskType(result);
}
mScanResult = result;
return true;
}
return false;
}
}
public void update(WifiInfo info, NetworkInfo networkInfo) {
synchronized (AccessPoint.class) {
if (info != null && ssid.equals(removeDoubleQuotes(info.getSSID()))) {
mRssi = info.getRssi();
mInfo = info;
mNetworkInfo = networkInfo;
} else {
mInfo = null;
mNetworkInfo = null;
}
}
}
public boolean isActive() {
return mNetworkInfo != null;
// return mNetworkInfo != null &&
// (networkId != INVALID_NETWORK_ID || mNetworkInfo.getState() != State.DISCONNECTED);
}
public void generateOpenNetworkConfig() {
synchronized (AccessPoint.class) {
if (security != SECURITY_NONE) {
throw new IllegalStateException();
}
if (mConfig != null) {
return;
}
mConfig = new WifiConfiguration();
mConfig.SSID = AccessPoint.convertToQuotedString(ssid);
mConfig.allowedKeyManagement.set(KeyMgmt.NONE);
}
}
private static String removeDoubleQuotes(String string) {
int length = string.length();
if ((length > 1) && (string.charAt(0) == '"')
&& (string.charAt(length - 1) == '"')) {
return string.substring(1, length - 1);
}
return string;
}
public static String convertToQuotedString(String string) {
return "\"" + string + "\"";
}
private static int getSecurity(WifiConfiguration config) {
if (config.allowedKeyManagement.get(KeyMgmt.WPA_PSK)) {
return SECURITY_PSK;
}
if (config.allowedKeyManagement.get(KeyMgmt.WPA_EAP) ||
config.allowedKeyManagement.get(KeyMgmt.IEEE8021X)) {
return SECURITY_EAP;
}
return (config.wepKeys[0] != null) ? SECURITY_WEP : SECURITY_NONE;
}
private static int getSecurity(ScanResult result) {
if (result.capabilities.contains("WEP")) {
return SECURITY_WEP;
} else if (result.capabilities.contains("PSK")) {
return SECURITY_PSK;
} else if (result.capabilities.contains("EAP")) {
return SECURITY_EAP;
}
return SECURITY_NONE;
}
private static PskType getPskType(ScanResult result) {
boolean wpa = result.capabilities.contains("WPA-PSK");
boolean wpa2 = result.capabilities.contains("WPA2-PSK");
if (wpa2 && wpa) {
return PskType.WPA_WPA2;
} else if (wpa2) {
return PskType.WPA2;
} else if (wpa) {
return PskType.WPA;
} else {
Log.w(TAG, "Received abnormal flag string: " + result.capabilities);
return PskType.UNKNOWN;
}
}
public int getLevel() {
if (mRssi == Integer.MAX_VALUE) {
return -1;
}
return WifiManager.calculateSignalLevel(mRssi, 4);
}
public WifiConfiguration getConfig() {
return mConfig;
}
public WifiInfo getInfo() {
return mInfo;
}
public NetworkInfo getNetworkInfo() {
return mNetworkInfo;
}
public DetailedState getState() {
return mNetworkInfo != null ? mNetworkInfo.getDetailedState() : null;
}
public String getBssid() {
return bssid;
}
public String getSsid() {
return ssid;
}
public int getSecurity() {
return security;
}
public int getNetworkId() {
return networkId;
}
public boolean isWpsAvailable() {
return wpsAvailable;
}
public PskType getPskType() {
return pskType;
}
public ScanResult getmScanResult() {
return mScanResult;
}
public int getmRssi() {
return mRssi;
}
public long getmSeen() {
return mSeen;
}
public WifiInfo getmInfo() {
return mInfo;
}
public NetworkInfo getmNetworkInfo() {
return mNetworkInfo;
}
public void setNetworkInfo(NetworkInfo mNetworkInfo) {
this.mNetworkInfo = mNetworkInfo;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(this.pskType == null ? -1 : this.pskType.ordinal());
dest.writeString(this.ssid);
dest.writeString(this.bssid);
dest.writeInt(this.security);
dest.writeInt(this.networkId);
dest.writeByte(this.wpsAvailable ? (byte) 1 : (byte) 0);
dest.writeInt(this.mRssi);
dest.writeLong(this.mSeen);
dest.writeParcelable(this.mScanResult, flags);
dest.writeParcelable(this.mConfig, flags);
dest.writeParcelable(this.mInfo, flags);
dest.writeParcelable(this.mNetworkInfo, flags);
}
protected AccessPoint(Parcel in) {
int tmpPskType = in.readInt();
this.pskType = tmpPskType == -1 ? null : PskType.values()[tmpPskType];
this.ssid = in.readString();
this.bssid = in.readString();
this.security = in.readInt();
this.networkId = in.readInt();
this.wpsAvailable = in.readByte() != 0;
this.mRssi = in.readInt();
this.mSeen = in.readLong();
this.mScanResult = in.readParcelable(ScanResult.class.getClassLoader());
this.mConfig = in.readParcelable(WifiConfiguration.class.getClassLoader());
this.mInfo = in.readParcelable(WifiInfo.class.getClassLoader());
this.mNetworkInfo = in.readParcelable(NetworkInfo.class.getClassLoader());
}
public static final Creator<AccessPoint> CREATOR = new Creator<AccessPoint>() {
@Override
public AccessPoint createFromParcel(Parcel source) {
return new AccessPoint(source);
}
@Override
public AccessPoint[] newArray(int size) {
return new AccessPoint[size];
}
};
}
package com.example.imlinkclient;
import android.app.Application;
import com.example.imlinkclient.helpr.MLinkServiceHelper;
import com.example.imlinkclient.helpr.WifiHelper;
public class ClientApplication extends Application {
private static ClientApplication application;
@Override
public void onCreate() {
super.onCreate();
application = this;
MLinkServiceHelper.getInstance().init(ClientApplication.this);
WifiHelper.getInstance().init(ClientApplication.this);
}
public static ClientApplication getAppContext() {
return application;
}
}
package com.example.imlinkclient;
import java.util.UUID;
public class Constants {
// AIDL客户端发过来的蓝牙数据
public final static int CMD_BLUETOOTH_DATA = 328202;
// 数据:key :"btData",类型:byte[]
public final static String KEY_BT_BYTES = "btData";
// WIFI配置信息
public final static int CMD_WIFI_CONFIG_INFO = 328203;
// key :"ssid",类型:String
public final static String KEY_SSID_STR = "ssid";
// key :"pass",类型:String
public final static String KEY_PASS_STR = "pass";
// key :"securityType",类型:byte
public final static String KEY_SECURITY_TYPE_BYTE = "securityType";
// key :" channel",类型:byte
public final static String KEY_CHANNEL_BYTE = "channel";
// Message types sent from the BluetoothChatService Handler
public static final int MESSAGE_STATE_CHANGE = 1;
public static final int MESSAGE_READ = 2;
public static final int MESSAGE_WRITE = 3;
public static final int MESSAGE_DEVICE_NAME = 4;
public static final int MESSAGE_TOAST = 5;
// Key names received from the BluetoothChatService Handler
public static final String DEVICE_NAME = "device_name";
public static final String TOAST = "toast";
// 车机连盒子00000000-deca-fade-deca-deafdecacafe
public static final UUID UUID_ACCEPT =
UUID.fromString("00000000-deca-fade-deca-deafdecacafe");
// 连接车机00000000-deca-fade-deca-deafdecacaff
public static final UUID UUID_CONNECT =
UUID.fromString("00000000-deca-fade-deca-deafdecacaff");
}
package com.example.imlinkclient;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.Parcelable;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import com.example.imlinkclient.helpr.BluetoothHelper;
import com.example.imlinkclient.helpr.MLinkServiceHelper;
import com.example.imlinkclient.helpr.WifiHelper;
import com.example.imlinkclient.utils.DataConvertUtils;
import java.lang.ref.WeakReference;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
public class MainClientActivity extends Activity implements View.OnClickListener {
public final static String TAG = "MainClientActivity";
private static final int REQUEST_ENABLE_BT = 3;
private Button mBtnBindAIDL;
private Button mBtnBindBluetooth;
private Button mBtnWIFIConnect;
private Button mBtnTest;
private ListView mListView;
private BluetoothHelper mBluetoothHelper;
private ArrayAdapter<String> mArrayAdapter;
private boolean isBTConnecting = false;
private MainHandler mainHandler;
private ProgressDialog mProgressDialog;
private TextView mTvStatusAIDL;
private TextView mTvStatusBT;
private NetworkConnectChangedReceiver mNetworkConnectChangedReceiver;
private BlePairBroadcastReceiver mBlePairBroadcastReceiver;
private static String mSsid;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initHandler();
initView();
initReceiver();
initWifi();
initBluetooth();
}
private void initReceiver() {
// 蓝牙广播
mBlePairBroadcastReceiver = new BlePairBroadcastReceiver();
registerReceiver(mBlePairBroadcastReceiver, new IntentFilter(BluetoothDevice.ACTION_PAIRING_REQUEST));
// wifi广播
registerNetworkConnectChangeReceiver();
}
private void initBluetooth() {
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (bluetoothAdapter == null) {
// Device doesn't support Bluetooth
toast("当前设备不支持蓝牙");
return;
}
if (!bluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
}
private void initHandler() {
mainHandler = new MainHandler(MainClientActivity.this);
mBluetoothHelper = new BluetoothHelper(mainHandler);
MLinkServiceHelper.getInstance().setHandler(mainHandler);
}
private void initWifi() {
if (!WifiHelper.getInstance().isWifiEnabled()) {
showAlertDialog("WIFI", "wifi还没打开,要打开吗?", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
WifiHelper.getInstance().openWiFi();
}
});
}
}
private void initView() {
mTvStatusAIDL = (TextView) findViewById(R.id.tv_bind_status_service);
mTvStatusBT = (TextView) findViewById(R.id.tv_bind_status_bt);
mBtnBindAIDL = (Button) findViewById(R.id.btn_bind_aidl);
mBtnBindBluetooth = (Button) findViewById(R.id.btn_bind_bluetooth);
mBtnWIFIConnect = (Button) findViewById(R.id.btn_wifi_connect);
mBtnTest = (Button) findViewById(R.id.btn_test);
mBtnBindBluetooth.setOnClickListener(this);
mBtnWIFIConnect.setOnClickListener(this);
mBtnBindAIDL.setOnClickListener(this);
mBtnTest.setOnClickListener(this);
mListView = (ListView) findViewById(R.id.lv_bt_data);
mArrayAdapter = new ArrayAdapter<String>(MainClientActivity.this, R.layout.message);
mListView.setAdapter(mArrayAdapter);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_bind_aidl:
// 绑定AIDL服务
MLinkServiceHelper.getInstance().bindMLinkService();
showProgress("连接AIDL服务");
mainHandler.postDelayed(mTimeOutRunnable, 60000);
break;
case R.id.btn_bind_bluetooth:
clickBluetooth();
break;
case R.id.btn_wifi_connect:
// 测试用
toast("连接wifi");
WifiHelper.getInstance().connectWifi("MX-vip", "mxcneeds");
break;
case R.id.btn_test:
// 测试用
String text = (String) mTvStatusAIDL.getText();
if (text.contains("成功")) {
byte[] bytes = new byte[2];
bytes[0] = 0;
bytes[1] = 1;
boolean b = false;
try {
b = MLinkServiceHelper.getInstance().getmIMlinkService().onWifiConnectionStatus(true, "test");
toast("onWifiConnectionStatus : " + b);
b = MLinkServiceHelper.getInstance().getmIMlinkService().onBtConnectionStatus(true, "test");
toast("onBtConnectionStatus : " + b);
b = MLinkServiceHelper.getInstance().getmIMlinkService().onReceivedBtData(bytes);
toast("onReceivedBtData : " + b);
} catch (RemoteException e) {
e.printStackTrace();
}
toast("status " + b);
} else {
toast("请先连接");
}
break;
}
}
private void clickBluetooth() {
if (!isBTConnecting) {
showAlertDialog("提示", "请确定车机已经打开Apple CarPlayd 蓝牙连接画面哦!", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
showProgress("请稍等, 如果车机出现配对码界面,请直接在车机点击 确定 ");
Log.e(TAG, " start progress");
mainHandler.postDelayed(mTimeOutRunnable, 90000);
// BMW 45831的蓝牙地址: 28:56:C1:05:2C:B3 , BMW 36493的蓝牙地址: A0:56:B2:E8:84:85
final BluetoothDevice remoteDevice = BluetoothAdapter.getDefaultAdapter().getRemoteDevice("A0:56:B2:E8:84:85");
Log.e(TAG, " getRemoteDevice");
if (remoteDevice != null) {
mBluetoothHelper.startAcceptThread();
Log.e(TAG, " startAcceptThread");
Log.e("MainClientActivity", " startAcceptThread");
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
mBluetoothHelper.startConnectThread(remoteDevice);
}
}, 200);
} else {
Toast.makeText(MainClientActivity.this, "remoteDevice == null", Toast.LENGTH_SHORT).show();
}
mBtnBindBluetooth.setText("停止绑定蓝牙");
}
});
} else {
mBluetoothHelper.unpairDevice();
mBluetoothHelper.stopAll();
mArrayAdapter.clear();
mBtnBindBluetooth.setText("绑定蓝牙");
}
isBTConnecting = !isBTConnecting;
}
public static class MainHandler extends Handler {
// 蓝牙状态改变
public static final int MSG_BT_STATUS = 0x01;
// 蓝牙数据收receiver
public static final int MSG_BT_DATA_R = 0x02;
// 蓝牙数据发transfer
public static final int MSG_BT_DATA_T = 0x03;
// WIFI配置信息
public static final int MSG_WIFI_CONFIG = 0x04;
// AIDL服务端绑定状态
public static final int MSG_AIDL_STATUS = 0x06;
private WeakReference<MainClientActivity> mWeakReference;
public MainHandler(MainClientActivity activity) {
mWeakReference = new WeakReference<>(activity);
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
MainClientActivity mainActivity = mWeakReference.get();
Bundle bundle = msg.getData();
switch (msg.what) {
case MSG_BT_STATUS:
mainActivity.toast("连接状态:" + (msg.arg1 == BluetoothHelper.STATE_CONNECTED));
boolean b1 = MLinkServiceHelper
.getInstance()
.onBtConnectionStatus(msg.arg1 == BluetoothHelper.STATE_CONNECTED,
(String) msg.obj);
mainActivity.toast("设置蓝牙状态onBtConnectionStatus :" + b1);
mainActivity.mTvStatusBT.setText(msg.arg1 == BluetoothHelper.STATE_CONNECTED? "连接成功": "未连接");
mainActivity.cancelProgress();
mainActivity.mainHandler.removeCallbacks(mainActivity.mTimeOutRunnable);
if (msg.arg1 ==BluetoothHelper.STATE_NONE &&mainActivity.isBTConnecting == true && mainActivity.mBtnBindBluetooth != null) {
// 蓝牙连接断开,把状态改回 蓝牙未连接 状态
mainActivity.clickBluetooth();
}
break;
case MSG_BT_DATA_R:
byte[] readBuf = (byte[]) msg.obj;
byte[] buffer = new byte[msg.arg1];
System.arraycopy(readBuf, 0, buffer, 0, msg.arg1);
boolean b = MLinkServiceHelper.getInstance().onReceivedBtData(buffer);
mainActivity.toast("发送数据状态onReceivedBtData :" + b);
mainActivity.mArrayAdapter.add("从车机接收 : "+Arrays.toString(buffer));
Log.d(TAG, "从车机接收 : " + Arrays.toString(buffer));
// mainActivity.mArrayAdapter.add("从车机接收 : "+ DataConvertUtils.toBinaryString(buffer));
break;
case MSG_BT_DATA_T:
byte[] btData = bundle.getByteArray(Constants.KEY_BT_BYTES);
// Log.d(TAG, "btData.length : " +btData.length);
// byte[] btData = (byte[]) msg.obj;
// byte[] realBytes = mainActivity.getRealBytes(btData);
Log.d("MLinkServiceHelper", "handler btData.length : " +btData.length);
mainActivity.mBluetoothHelper.write(btData);
mainActivity.mArrayAdapter.add("写入到车机 : "+ Arrays.toString(btData));
Log.d(TAG, "写入到车机 : "+ Arrays.toString(btData));
break;
case MSG_WIFI_CONFIG:
Bundle data = msg.getData();
mSsid = data.getString(Constants.KEY_SSID_STR);
String password = data.getString(Constants.KEY_PASS_STR);
WifiHelper.getInstance().connectWifi(mSsid, password);
break;
case MSG_AIDL_STATUS:
mainActivity.cancelProgress();
mainActivity.mainHandler.removeCallbacks(mainActivity.mTimeOutRunnable);
int status = msg.arg1;
if (status == 1) {
mainActivity.toast("AIDL连接成功");
mainActivity.mTvStatusAIDL.setText("AIDL连接成功");
mainActivity.mBtnBindAIDL.setClickable(false);
} else {
mainActivity.toast("AIDL连接断开");
mainActivity.mTvStatusAIDL.setText("AIDL连接断开");
mainActivity.mBtnBindAIDL.setClickable(true);
}
break;
default:
break;
}
}
}
public void toast(String msg) {
Toast.makeText(MainClientActivity.this, msg, Toast.LENGTH_SHORT).show();
}
public class BlePairBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction() == BluetoothDevice.ACTION_PAIRING_REQUEST) {
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
int pin = intent.getIntExtra(BluetoothDevice.EXTRA_PAIRING_KEY, 1234);
toast("pin : " + pin + " 请在车机点击确定");
device.setPin(("" + pin).getBytes());
try {
// 这里是系统权限,需要系统签名
setPairingConfirmation(BluetoothDevice.class, device, true);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
public void setPairingConfirmation(Class<?> btClass, BluetoothDevice device, boolean isConfirm) throws Exception {
Method setPairingConfirmation = btClass.getDeclaredMethod("setPairingConfirmation", boolean.class);
setPairingConfirmation.invoke(device, isConfirm);
}
private void showAlertDialog(String title, String message, DialogInterface.OnClickListener listener) {
new AlertDialog.Builder(this).setIcon(R.mipmap.ic_launcher).setTitle(title)
.setMessage(message).setPositiveButton("确定", listener).create().show();
}
private void showProgress(String message) {
mProgressDialog = new ProgressDialog(this);
mProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);//转盘
mProgressDialog.setCancelable(false);
mProgressDialog.setCanceledOnTouchOutside(false);
mProgressDialog.setTitle("提示");
mProgressDialog.setMessage(message);
mProgressDialog.show();
}
private void cancelProgress() {
if (mProgressDialog != null && mProgressDialog.isShowing()) {
mProgressDialog.cancel();
}
}
Runnable mTimeOutRunnable = new Runnable() {
@Override
public void run() {
cancelProgress();
toast("连接失败,请稍后重试!");
if (isBTConnecting == true && mBtnBindBluetooth != null) {
clickBluetooth();
}
}
};
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case REQUEST_ENABLE_BT:
if (resultCode == Activity.RESULT_OK) {
} else {
Log.d(TAG, "BT not enabled");
Toast.makeText(MainClientActivity.this, "请开启蓝牙",
Toast.LENGTH_SHORT).show();
MainClientActivity.this.finish();
}
}
}
private void registerNetworkConnectChangeReceiver() {
IntentFilter filter = new IntentFilter();
filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
filter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
filter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION);
mNetworkConnectChangedReceiver = new NetworkConnectChangedReceiver();
registerReceiver(mNetworkConnectChangedReceiver, filter);
}
class NetworkConnectChangedReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(action)) {
Parcelable parcelableExtra = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
WifiInfo wifiInfo = intent.getParcelableExtra(WifiManager.EXTRA_WIFI_INFO);
if (wifiInfo != null) {
String ssid = wifiInfo.getSSID();
if (null != parcelableExtra) {
if(("\""+mSsid+"\"").equals(ssid)) {
String bssid = intent.getStringExtra(WifiManager.EXTRA_BSSID);
NetworkInfo networkInfo = (NetworkInfo) parcelableExtra;
NetworkInfo.State state = networkInfo.getState();
MLinkServiceHelper.getInstance().onWifiConnectionStatus(state == NetworkInfo.State.CONNECTED, bssid);
}
}
}
}
}
}
@Override
protected void onDestroy() {
super.onDestroy();
unRegisterReceiver();
}
private void unRegisterReceiver() {
if (mNetworkConnectChangedReceiver != null) {
unregisterReceiver(mNetworkConnectChangedReceiver);
}
if (mBlePairBroadcastReceiver != null) {
unregisterReceiver(mBlePairBroadcastReceiver);
}
}
}
package com.example.imlinkclient.helpr;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.util.Log;
import com.example.imlinkclient.MainClientActivity;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Set;
import java.util.UUID;
import static com.example.imlinkclient.Constants.UUID_ACCEPT;
import static com.example.imlinkclient.Constants.UUID_CONNECT;
/**
* 蓝牙连接Helper
* 注意:车机的蓝牙连接分两步,
* 第一步是,车盒端主动发起连接,这个时候车机会在连接完成后断开连接
* 第二步时,提前开启一个蓝牙的accept监听,车机在主动断开连接后,会主动发起对车盒的连接。
* 参考: https://github.com/googlearchive/android-BluetoothChat
*
*/
public class BluetoothHelper {
private static final String TAG = "BluetoothHelper";
private int mCurrent_State;
public static final int STATE_NONE = 0; // we're doing nothing
public static final int STATE_LISTEN = 1; // now listening for incoming connections
public static final int STATE_CONNECTING = 2; // now initiating an outgoing connection
public static final int STATE_CONNECTED = 3; // now connected to a remote device
// Name for the SDP record when creating server socket
private static final String NAME_SECURE = "BluetoothChatSecure";
private final BluetoothAdapter mAdapter;
private CommunicateThread mCommunicateThread;
private AcceptThread mAcceptThread;
private ConnectThread mConnectThread;
private final MainClientActivity.MainHandler mMainHandler;
private BluetoothDevice mDevice;
public BluetoothHelper(MainClientActivity.MainHandler mainHandler) {
mMainHandler = mainHandler;
mAdapter = BluetoothAdapter.getDefaultAdapter();
}
// 主动发起连接
public void startConnectThread(BluetoothDevice device) {
mDevice = device;
mConnectThread = new ConnectThread(device);
mConnectThread.start();
}
private class ConnectThread extends Thread {
private final BluetoothSocket mmSocket;
private final BluetoothDevice mDevice;
public ConnectThread(BluetoothDevice device) {
mDevice = device;
BluetoothSocket tmp = null;
// Get a BluetoothSocket for a connection with the
// given BluetoothDevice
try {
/*** 第一步 主动发起连接**/
tmp = device.createInsecureRfcommSocketToServiceRecord(UUID_CONNECT);
Log.e("MainClientActivity", " createInsecureRfcommSocketToServiceRecord");
} catch (IOException e) {
Log.e(TAG, "ConnectThread 连接失败: createRfcommSocketToServiceRecord 等待车机回连");
cancel();
} catch (Exception e) {
Log.e("MainClientActivity", " exception : " + e.getMessage());
}
mmSocket = tmp;
}
public void run() {
Log.i(TAG, "BEGIN mConnectThread ");
setName("ConnectThread");
// Always cancel discovery because it will slow down a connection
mAdapter.cancelDiscovery();
// Make a connection to the BluetoothSocket
try {
// This is a blocking call and will only return on a
// successful connection or an exception
mmSocket.connect();
} catch (IOException e) {
// Close the socket
Log.e(TAG, "ConnectThread 连接失败: mmSocket.connect();");
try {
mmSocket.close();
} catch (IOException e2) {
Log.e(TAG, "ConnectThread 连接失败: mmSocket.close();");
}
return;
}
Log.e(TAG, "ConnectThread 连接成功");
InputStream inputStream = null;
try {
inputStream = mmSocket.getInputStream();
} catch (IOException e) {
e.printStackTrace();
Log.e(TAG, "ConnectThread 连接断开: mmSocket.getInputStream();");
cancel();
}
byte[] buffer = new byte[1024];
while (true) {
try {
// Read from the InputStream
inputStream.read(buffer);
Log.d(TAG, " ConnectThread 读取数据 : " + Arrays.toString(buffer));
} catch (IOException e) {
Log.e(TAG, "ConnectThread 连接断开: inputStream.read(buffer);");
cancel();
break;
}
}
}
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) {
Log.e(TAG, "close() of connect socket failed", e);
}
}
}
/** 被动连接 线程**/
public void startAcceptThread() {
mAcceptThread = new AcceptThread();
mAcceptThread.start();
}
private class AcceptThread extends Thread {
// The local server socket
private final BluetoothServerSocket mmServerSocket;
public AcceptThread() {
BluetoothServerSocket tmp = null;
// Create a new listening server socket
try {
tmp = mAdapter.listenUsingRfcommWithServiceRecord(NAME_SECURE,
UUID_ACCEPT);
} catch (IOException e) {
Log.e(TAG, "AcceptThread 连接失败: listenUsingRfcommWithServiceRecord" + e.getMessage());
}
mmServerSocket = tmp;
}
public void run() {
setName("AcceptThread");
BluetoothSocket socket = null;
while (true) {
try {
/*** 第二步 等待车机主动发起连接 **/
socket = mmServerSocket.accept();
Log.e(TAG, "AcceptThread 监听连接 accept");
if (socket != null) {
connected(socket, socket.getRemoteDevice());
Log.e(TAG, "AcceptThread 连接成功");
break;
}
} catch (IOException e) {
Log.e(TAG, "AcceptThread 连接失败 accept() failed" + e.getMessage());
cancel();
sendBTDisconnect();
break;
}
}
Log.i(TAG, "END mAcceptThread");
}
public void cancel() {
Log.d(TAG, "cancel " + this);
try {
mmServerSocket.close();
} catch (IOException e) {
Log.e(TAG, "close() of server failed", e);
}
}
}
private synchronized void connected(BluetoothSocket socket, BluetoothDevice device) {
Log.d(TAG, "connected");
// Cancel the thread that completed the connection
if (mAcceptThread != null) {
mAcceptThread.cancel();
mAcceptThread = null;
}
// Start the thread to manage the connection and perform transmissions
mCommunicateThread = new CommunicateThread(socket);
mCommunicateThread.start();
sendBTConnected(device);
}
public void write(byte[] out) {
// Create temporary object
CommunicateThread r;
// Synchronize a copy of the ConnectedThread
synchronized (this) {
if (mCurrent_State != STATE_CONNECTED) return;
r = mCommunicateThread;
}
// Perform the write unsynchronized
r.write(out);
}
/**
* This thread runs during a connection with a remote device.
* It handles all incoming and outgoing transmissions.
*/
private class CommunicateThread extends Thread {
private final BluetoothSocket mmSocket;
private final InputStream mmInStream;
private final OutputStream mmOutStream;
public CommunicateThread(BluetoothSocket socket) {
Log.d(TAG, "create ConnectedThread");
mmSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
// Get the BluetoothSocket input and output streams
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) {
Log.e(TAG, "CommunicateThread 连接失败 temp sockets not created", e);
sendBTDisconnect();
cancel();
}
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
public void run() {
byte[] buffer = new byte[1024];
int length;
// Keep listening to the InputStream while connected
while (true) {
try {
// Read from the InputStream
length = mmInStream.read(buffer);
readData(length, buffer);
Log.d(TAG, " read : " + Arrays.toString(buffer));
} catch (IOException e) {
cancel();
sendBTDisconnect();
Log.d(TAG, "CommunicateThread 连接断开 mmInStream.read(buffer)", e);
break;
}
}
}
/**
* Write to the connected OutStream.
*
* @param buffer The bytes to write
*/
public void write(byte[] buffer) {
try {
mmOutStream.write(buffer);
Log.e(TAG, "CommunicateThread 写入数据:" + Arrays.toString(buffer));
} catch (IOException e) {
Log.e(TAG, "Exception during write", e);
}
}
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) {
Log.e(TAG, "close() of connect socket failed", e);
}
}
}
public void stopAll() {
if (mAcceptThread != null) {
mAcceptThread.cancel();
mAcceptThread = null;
}
if (mConnectThread != null) {
mConnectThread.cancel();
mConnectThread = null;
}
if (mCommunicateThread != null) {
mCommunicateThread.cancel();
mCommunicateThread = null;
}
}
//得到配对的设备列表,清除已配对的设备
public void removePairDevice(){
if(mAdapter!=null){
Set<BluetoothDevice> bondedDevices = mAdapter.getBondedDevices();
for(BluetoothDevice device : bondedDevices ){
unpairDevice(device);
}
}
}
public void unpairDevice() {
if (mDevice != null) {
unpairDevice(mDevice);
Set<BluetoothDevice> bondedDevices = mAdapter.getBondedDevices();
for (BluetoothDevice device :
bondedDevices) {
}
}
}
//反射来调用BluetoothDevice.removeBond取消设备的配对
public void unpairDevice(BluetoothDevice device) {
try {
Method m = device.getClass()
.getMethod("removeBond", (Class[]) null);
m.invoke(device, (Object[]) null);
} catch (Exception e) {
Log.e(TAG, e.getMessage());
}
}
/** handle 命令抽取 start**/
private void sendBTConnected(BluetoothDevice device) {
mCurrent_State = STATE_CONNECTED;
mMainHandler.obtainMessage(MainClientActivity.MainHandler.MSG_BT_STATUS, STATE_CONNECTED, -1, device.getAddress())
.sendToTarget();
}
private void sendBTDisconnect() {
mCurrent_State = STATE_NONE;
mMainHandler.obtainMessage(MainClientActivity.MainHandler.MSG_BT_STATUS, STATE_NONE, -1)
.sendToTarget();
}
// 从车机端读取信息
private void readData(int length, byte[] buffer) {
mMainHandler.obtainMessage(MainClientActivity.MainHandler.MSG_BT_DATA_R, length, -1, buffer)
.sendToTarget();
}
/**
* handle 命令抽取 end
**/
public int getState() {
return mCurrent_State;
}
}
package com.example.imlinkclient.helpr;
import android.app.Application;
import android.app.Service;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteException;
import android.util.Log;
import com.example.imlinkclient.Constants;
import com.example.imlinkclient.MainClientActivity;
import com.mxnavi.mlink.serversdk.service.IMlinkService;
import com.mxnavi.mlink.serversdk.service.IMlinkServiceClient;
import java.util.Arrays;
/**
* AIDL连接
*/
public class MLinkServiceHelper {
private final static String TAG = "MLinkServiceHelper";
private static volatile MLinkServiceHelper mInstance = null;
private Context mContext;
private boolean mServiceBounded;
private IMlinkService mIMlinkService;
private MainClientActivity.MainHandler mMainHandler;
private MLinkServiceHelper() {
}
public static MLinkServiceHelper getInstance() {
// 二次校验,防止多线程调用导致出现多个实例
if (mInstance == null) {
synchronized (MLinkServiceHelper.class) {
if (mInstance == null) {
mInstance = new MLinkServiceHelper();
}
}
}
return mInstance;
}
public void init(Application application) {
mContext = application.getApplicationContext();
}
public void setHandler(MainClientActivity.MainHandler handler) {
mMainHandler = handler;
}
public Context getApplicationContext() {
return mContext;
}
public boolean bindMLinkService() {
if (mServiceBounded) {
return true;
}
Intent intent = new Intent();
// Action:com.mxnavi.mlink.ACTION_BIND_MLINK_SERVICE
// Package:com.mxnavi.applauncher
intent.setAction("com.mxnavi.mlink.ACTION_BIND_MLINK_SERVICE");
intent.setPackage("com.mxnavi.applauncher");
mServiceBounded = mContext.bindService(intent, mConnection, Service.BIND_AUTO_CREATE);
return mServiceBounded;
}
ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mIMlinkService = IMlinkService.Stub.asInterface(service);
try {
if (mIMlinkService != null){
mIMlinkService.registerMlinkServiceClient(mMlinkClient);
}
} catch (RemoteException | SecurityException e) {
e.printStackTrace();
}
mMainHandler.obtainMessage(MainClientActivity.MainHandler.MSG_AIDL_STATUS, 1, -1)
.sendToTarget();
Log.d(TAG, "onServiceConnected aidl连接成功");
}
@Override
public void onServiceDisconnected(ComponentName name) {
try {
mIMlinkService.unregisterMlinkServiceClient(mMlinkClient);
} catch (RemoteException | SecurityException e) {
e.printStackTrace();
}
mMainHandler.obtainMessage(MainClientActivity.MainHandler.MSG_AIDL_STATUS, 0, -1)
.sendToTarget();
Log.d(TAG, "onServiceConnected aidl连接断开");
}
};
IMlinkServiceClient.Stub mMlinkClient = new IMlinkServiceClient.Stub() {
@Override
public void onConnectionStateChanged(boolean isConnected) throws RemoteException {
Log.d(TAG, "onConnectionStateChanged :" + isConnected);
}
@Override
public void onHUCommand(final int cmd, final Bundle bundle) throws RemoteException {
Log.d(TAG, "接收到aidl数据 onHUCommand : " + cmd + " bundle : " + bundle.toString());
switch (cmd) {
case Constants.CMD_BLUETOOTH_DATA:
// 发送蓝牙数据
sendMessage(MainClientActivity.MainHandler.MSG_BT_DATA_T, bundle);
// Log.d(TAG, "接收到aidl蓝牙数据 onHUCommand : " + cmd + " bundle : " + Arrays.toString(btData));
// byte[] btData = bundle.getByteArray(Constants.KEY_BT_BYTES);
// Log.d(TAG, "onHUCommand btData.length : " +btData.length);
// mMainHandler.obtainMessage(MainClientActivity.MainHandler.MSG_BT_DATA_T, -1, -1, btData).sendToTarget();
break;
case Constants.CMD_WIFI_CONFIG_INFO:
// 配置 wifi
sendMessage(MainClientActivity.MainHandler.MSG_WIFI_CONFIG, bundle);
break;
}
}
};
private void sendMessage(int what, Bundle data) {
Message message = mMainHandler.obtainMessage(what);
message.setData(data);
message.sendToTarget();
}
/**
* mIMlinkService 接口包装 start
**/
public boolean onBtConnectionStatus(boolean isConnected, String mac) {
if (mIMlinkService != null) {
try {
Log.d(TAG, "onBtConnectionStatus 蓝牙连接状态: "+isConnected +" mac :" + mac);
return mIMlinkService.onBtConnectionStatus(isConnected, mac);
} catch (RemoteException | SecurityException e) {
e.printStackTrace();
}
}
return false;
}
public boolean onReceivedBtData(byte[] data) {
if (mIMlinkService != null) {
try {
Log.d(TAG, "onReceivedBtData 发送数据: " + Arrays.toString(data));
return mIMlinkService.onReceivedBtData(data);
} catch (RemoteException | SecurityException e) {
e.printStackTrace();
}
}
return false;
}
public boolean onWifiConnectionStatus(boolean isConnected, String mac) {
if (mIMlinkService != null) {
try {
return mIMlinkService.onWifiConnectionStatus(isConnected, mac);
} catch (RemoteException | SecurityException e) {
e.printStackTrace();
}
}
return false;
}
public IMlinkService getmIMlinkService() {
return mIMlinkService;
}
/** mIMlinkService 接口包装 end **/
}
package com.example.imlinkclient.helpr;
import android.content.Context;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.util.Log;
import com.example.imlinkclient.MainClientActivity;
import java.util.List;
/**
* WIFI
* 参考:https://stackoverflow.com/questions/8818290/how-do-i-connect-to-a-specific-wi-fi-network-in-android-programmatically
* https://developer.aliyun.com/article/12840
* https://developer.android.google.cn/reference/android/net/wifi/WifiConfiguration
* https://github.com/ZhangJianIsAStark/Demos/blob/master/wifitest
*/
public class WifiHelper {
private final static String TAG = "WifiHelper";
private static volatile WifiHelper mInstance = null;
private WifiManager mWifiManager;
private WifiInfo mWifiInfo;
private WifiHelper() {
}
public void init(Context context) {
// 取得WifiManager对象
mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
// 取得WifiInfo对象
mWifiInfo = mWifiManager.getConnectionInfo();
}
public static WifiHelper getInstance() {
// 二次校验,防止多线程调用导致出现多个实例
if (mInstance == null) {
synchronized (WifiHelper.class) {
if (mInstance == null) {
mInstance = new WifiHelper();
}
}
}
return mInstance;
}
private WifiConfiguration isExist(String SSID) {
List<WifiConfiguration> existingConfigs = mWifiManager.getConfiguredNetworks();
if (existingConfigs != null) {
for (WifiConfiguration existingConfig : existingConfigs) {
if (existingConfig.SSID.equals("\"" + SSID + "\"") /*&& existingConfig.preSharedKey.equals("\"" + password + "\"")*/) {
return existingConfig;
}
}
}
return null;
}
/**
* 获取WIFI的开关状态
*
* @return WIFI的可用状态
*/
public boolean isWifiEnabled() {
return null != mWifiManager && mWifiManager.isWifiEnabled();
}
/**
* 打开Wifi
*/
public void openWiFi() {
if (!isWifiEnabled() && null != mWifiManager) {
mWifiManager.setWifiEnabled(true);
}
}
/**
* 关闭Wifi
*/
public void closeWiFi() {
if (isWifiEnabled() && null != mWifiManager) {
mWifiManager.setWifiEnabled(false);
}
}
/**
* 根据SSID和密码连接wifi
* 参考:https://stackoverflow.com/questions/8818290/how-do-i-connect-to-a-specific-wi-fi-network-in-android-programmatically
* @param ssid
* @param password
*/
public void connectWifi(String ssid, String password) {
WifiConfiguration wifiConfig = new WifiConfiguration();
wifiConfig.SSID = String.format("\"%s\"", ssid);
wifiConfig.preSharedKey = String.format("\"%s\"", password);
int netId = mWifiManager.addNetwork(wifiConfig);
mWifiManager.disconnect();
mWifiManager.enableNetwork(netId, true);
mWifiManager.reconnect();
}
}
\ No newline at end of file
package com.example.imlinkclient.utils;
public class DataConvertUtils {
/**
* 把byte数组转化为二进制样式的字符串
* @param array
* @return
*/
public static String toBinaryString(byte[] array) {
if (array == null) {
return "null";
}
if (array.length == 0) {
return "[]";
}
StringBuilder sb = new StringBuilder();
sb.append('[');
sb.append(array[0]);
for (int i = 1; i < array.length; i++) {
sb.append(", ");
sb.append(Integer.toBinaryString(array[i]));
}
sb.append(']');
return sb.toString();
}
/**
* 把bytes后面的0去掉
* @param bytes
* @return
*/
public static byte[] getRealBytes(byte[] bytes) {
int length = 0;
for (int i = bytes.length-1; i >= 0; i--) {
if (bytes[i] != 0) {
length = i;
break;
}
}
length += 1;
byte[] realBytes = new byte[length];
System.arraycopy(bytes, 0, realBytes, 0, length);
return realBytes;
}
}
package com.example.imlinkclient.utils;
import java.lang.reflect.Field;
public class InvokeUtil{
public static <T> T getDeclaredField(Class cls, String fieldName, Object object) {
try {
Field field = cls.getDeclaredField(fieldName);
T o = (T) field.get(object);
return o;
} catch (NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
}
return null;
}
}
package com.example.imlinkclient.view;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.util.AttributeSet;
import android.widget.RelativeLayout;
/**
* author: jack
* date: 2018/8/30 18:12
* desc:Launcher界面基类
*/
public abstract class BaseLauncherView extends RelativeLayout {
private static final String TAG = "BaseLauncherView";
//UI state
public static final int STATE_NO_CONNECT = 0;
public static final int STATE_CONNECT = 1;
public static final int STATE_CALL = 2;
protected final Context mContext;
protected Context mReadResContext;
//view
protected RelativeLayout mRlRoot;
public BaseLauncherView(Context context) {
this(context, null);
}
public BaseLauncherView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public BaseLauncherView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.mContext = context;
try {
mReadResContext = mContext.createPackageContext(Constants.PACKAGE_NAME, Context.CONTEXT_IGNORE_SECURITY | Context.CONTEXT_INCLUDE_CODE);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
onInit(context, attrs, defStyleAttr);
}
public abstract void onInit(Context context, AttributeSet attrs, int defStyleAttr);
/**
* 启动App
*/
protected void startupApp() {
Intent targetIntent = getContext().getPackageManager().getLaunchIntentForPackage(Constants.PACKAGE_NAME);
mContext.startActivity(targetIntent);
}
protected void toHome() {
Intent home = new Intent(Intent.ACTION_MAIN);
home.addCategory(Intent.CATEGORY_HOME);
getContext().startActivity(home);
}
}
package com.example.imlinkclient.view;
public class Constants {
//应用包名
public static final String PACKAGE_NAME = "com.example.imlinkclient";
}
package com.example.imlinkclient.view;
import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.LinearLayout;
import com.example.imlinkclient.R;
public class ItemView extends BaseLauncherView{
public ItemView(Context context) {
super(context);
}
@Override
public void onInit(Context context, AttributeSet attrs, int defStyleAttr) {
LayoutInflater.from(context).inflate(R.layout.launcher_view, this);
LinearLayout root = (LinearLayout) findViewById(R.id.ll_root);
root.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startupApp();
}
});
}
}
<?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"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:id="@+id/ll_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="服务绑定状态: " />
<TextView
android:id="@+id/tv_bind_status_service"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="false" />
</LinearLayout>
<LinearLayout
android:id="@+id/ll_2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@+id/ll_1"
android:padding="10dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="蓝牙绑定状态: " />
<TextView
android:id="@+id/tv_bind_status_bt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="false" />
</LinearLayout>
<!-- <LinearLayout-->
<!-- android:id="@+id/ll_3"-->
<!-- android:layout_width="wrap_content"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:layout_toRightOf="@+id/ll_2"-->
<!-- android:padding="10dp">-->
<!-- <TextView-->
<!-- android:layout_width="wrap_content"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:text="蓝牙绑定状态: " />-->
<!-- <TextView-->
<!-- android:id="@+id/tv_bind_receiver"-->
<!-- android:layout_width="wrap_content"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:text="false" />-->
<!-- </LinearLayout>-->
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button
android:id="@+id/btn_bind_aidl"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginTop="10dp"
android:padding="10dp"
android:text="绑定远程服务" />
<Button
android:id="@+id/btn_bind_bluetooth"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_toRightOf="@id/btn_bind_aidl"
android:layout_marginTop="10dp"
android:padding="10dp"
android:text="绑定蓝牙" />
<Button
android:id="@+id/btn_wifi_connect"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:layout_toRightOf="@id/btn_bind_bluetooth"
android:layout_marginLeft="10dp"
android:padding="10dp"
android:visibility="gone"
android:text="wifi连接" />
<Button
android:id="@+id/btn_test"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:layout_toRightOf="@id/btn_bind_bluetooth"
android:layout_marginLeft="10dp"
android:padding="10dp"
android:visibility="gone"
android:text="测试AIDL接口" />
</RelativeLayout>
<ListView
android:id="@+id/lv_bt_data"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:stackFromBottom="true"
android:transcriptMode="alwaysScroll" />
</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:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/ll_root"
android:gravity="center">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="25sp"
android:text="IMLinkClient"/>
</LinearLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2014 The Android Open Source Project
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.
-->
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dp"
android:maxLines="3"
android:textSize="18sp"
/>
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#6200EE</color>
<color name="colorPrimaryDark">#3700B3</color>
<color name="colorAccent">#03DAC5</color>
</resources>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<integer name="launcher_index">5</integer>
</resources>
\ No newline at end of file
<resources>
<string name="app_name">IMLinkClient</string>
</resources>
\ No newline at end of file
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="@android:style/Theme.NoTitleBar.Fullscreen">
<item name="android:windowAnimationStyle">@style/Animation</item>
</style>
<style name="MyAppTheme" parent="@android:style/Theme.NoTitleBar.Fullscreen">
</style>
<style name="Animation">
<item name="android:activityOpenEnterAnimation">@null</item>
<item name="android:activityOpenExitAnimation">@null</item>
<item name="android:activityCloseEnterAnimation">@null</item>
<item name="android:activityCloseExitAnimation">@null</item>
<item name="android:taskOpenEnterAnimation">@null</item>
<item name="android:taskOpenExitAnimation">@null</item>
<item name="android:taskCloseEnterAnimation">@null</item>
<item name="android:taskCloseExitAnimation">@null</item>
<item name="android:taskToFrontEnterAnimation">@null</item>
<item name="android:taskToFrontExitAnimation">@null</item>
<item name="android:taskToBackEnterAnimation">@null</item>
<item name="android:taskToBackExitAnimation">@null</item>
</style>
</resources>
\ No newline at end of file
include ':imlinkclient'
include ':app'
rootProject.name = "IMLinkDemo"
\ No newline at end of file
目录说明:
## IMLinkDemo
宝马车机蓝牙连接和发送信息的demo, 其中的 “app” module是前期为了测试用的,现在已经不需要。
主要代码在 “imlinkclient”
## Demo操作手册.doc
整个流程的操作手册
## signTools.zip
用于系统签名的,写个批处理只是为了方便,只要能系统签名就好,不一定要用这个
\ No newline at end of file
File added
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