├── .github └── FUNDING.yml ├── .gitignore ├── .idea ├── codeStyles │ └── Project.xml ├── encodings.xml ├── gradle.xml ├── jarRepositories.xml ├── misc.xml └── runConfigurations.xml ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro ├── release │ ├── app-release.apk │ └── output.json └── src │ └── main │ ├── AndroidManifest.xml │ ├── assets │ └── app-debug.apk │ ├── java │ └── com │ │ └── projection │ │ └── car │ │ ├── ForgroundService.java │ │ ├── MainActivity.java │ │ ├── MediaCodecTool.java │ │ ├── MsgProcess.java │ │ └── Utils.java │ ├── proto │ ├── CarlifeAccelerationProto.proto │ ├── CarlifeAuthenRequestProto.proto │ ├── CarlifeAuthenResponseProto.proto │ ├── CarlifeAuthenResultProto.proto │ ├── CarlifeBTHfpConnectionProto.proto │ ├── CarlifeBTHfpIndicationProto.proto │ ├── CarlifeBTHfpRequestProto.proto │ ├── CarlifeBTHfpResponseProto.proto │ ├── CarlifeBTHfpStatusRequestProto.proto │ ├── CarlifeBTHfpStatusResponseProto.proto │ ├── CarlifeBTIdentifyResultIndProto.proto │ ├── CarlifeBTPairInfoProto.proto │ ├── CarlifeBTStartIdentifyReqProto.proto │ ├── CarlifeBTStartPairReqProto.proto │ ├── CarlifeCallRecordsListProto.proto │ ├── CarlifeCallRecordsProto.proto │ ├── CarlifeCarGpsProto.proto │ ├── CarlifeCarHardKeyCodeProto.proto │ ├── CarlifeCarSpeedProto.proto │ ├── CarlifeConnectExceptionProto.proto │ ├── CarlifeContactsListProto.proto │ ├── CarlifeContactsProto.proto │ ├── CarlifeDeviceInfoProto.proto │ ├── CarlifeErrorCodeProto.proto │ ├── CarlifeFeatureConfigListProto.proto │ ├── CarlifeFeatureConfigProto.proto │ ├── CarlifeGearInfoProto.proto │ ├── CarlifeGyroscopeProto.proto │ ├── CarlifeMediaInfoListProto.proto │ ├── CarlifeMediaInfoProto.proto │ ├── CarlifeMediaProgressBarProto.proto │ ├── CarlifeModuleStatusListProto.proto │ ├── CarlifeModuleStatusProto.proto │ ├── CarlifeMusicInitProto.proto │ ├── CarlifeNaviAssitantGuideInfoProto.proto │ ├── CarlifeNaviNextTurnInfoProto.proto │ ├── CarlifeOilProto.proto │ ├── CarlifeProtocolVersionMatchStatusProto.proto │ ├── CarlifeProtocolVersionProto.proto │ ├── CarlifeStatisticsInfoProto.proto │ ├── CarlifeSubscribeMobileCarLifeInfoListProto.proto │ ├── CarlifeSubscribeMobileCarLifeInfoProto.proto │ ├── CarlifeTTSInitProto.proto │ ├── CarlifeTouchActionProto.proto │ ├── CarlifeTouchEventAllDeviceProto.proto │ ├── CarlifeTouchEventDeviceProto.proto │ ├── CarlifeTouchEventProto.proto │ ├── CarlifeTouchFlingProto.proto │ ├── CarlifeTouchScrollProto.proto │ ├── CarlifeTouchSinglePointProto.proto │ ├── CarlifeVehicleInfoListProto.proto │ ├── CarlifeVehicleInfoProto.proto │ ├── CarlifeVideoEncoderInfoProto.proto │ └── CarlifeVideoFrameRateProto.proto │ └── res │ ├── drawable │ └── ic_launcher_background.xml │ ├── layout │ └── activity_main.xml │ ├── mipmap-hdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-mdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── values │ ├── colors.xml │ ├── strings.xml │ └── styles.xml │ └── xml │ ├── accessibility.xml │ ├── accessory_filter.xml │ └── c.xml ├── build.gradle ├── demo.gif ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── plugin ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── projection │ │ └── car │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── projection │ │ │ └── car │ │ │ └── MainActivity.java │ └── res │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable │ │ └── ic_launcher_background.xml │ │ ├── layout │ │ └── activity_main.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ └── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── projection │ └── car │ └── ExampleUnitTest.java ├── screen_1.jpg └── settings.gradle /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 12 | polar: # Replace with a single Polar username 13 | buy_me_a_coffee: # Replace with a single Buy Me a Coffee username 14 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 15 | 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | /.idea/navEditor.xml 9 | /.idea/assetWizardSettings.xml 10 | .DS_Store 11 | /build 12 | /captures 13 | .externalNativeBuild 14 | -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | xmlns:android 14 | 15 | ^$ 16 | 17 | 18 | 19 |
20 |
21 | 22 | 23 | 24 | xmlns:.* 25 | 26 | ^$ 27 | 28 | 29 | BY_NAME 30 | 31 |
32 |
33 | 34 | 35 | 36 | .*:id 37 | 38 | http://schemas.android.com/apk/res/android 39 | 40 | 41 | 42 |
43 |
44 | 45 | 46 | 47 | .*:name 48 | 49 | http://schemas.android.com/apk/res/android 50 | 51 | 52 | 53 |
54 |
55 | 56 | 57 | 58 | name 59 | 60 | ^$ 61 | 62 | 63 | 64 |
65 |
66 | 67 | 68 | 69 | style 70 | 71 | ^$ 72 | 73 | 74 | 75 |
76 |
77 | 78 | 79 | 80 | .* 81 | 82 | ^$ 83 | 84 | 85 | BY_NAME 86 | 87 |
88 |
89 | 90 | 91 | 92 | .* 93 | 94 | http://schemas.android.com/apk/res/android 95 | 96 | 97 | ANDROID_ATTRIBUTE_ORDER 98 | 99 |
100 |
101 | 102 | 103 | 104 | .* 105 | 106 | .* 107 | 108 | 109 | BY_NAME 110 | 111 |
112 |
113 |
114 |
115 |
116 |
-------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 21 | 22 | -------------------------------------------------------------------------------- /.idea/jarRepositories.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 14 | 15 | 19 | 20 | 24 | 25 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CarProjection 2 | 3 | 本项目基于carlife 协议投屏,安卓10以上无需root,可反向触控,仅用作研究学习 4 | 5 | 6 | # screenshot 7 | ![](https://github.com/aa112901/CarProjection/blob/main/screen_1.jpg) 8 | ![](https://github.com/aa112901/CarProjection/blob/main/demo.gif) 9 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | apply plugin: 'com.google.protobuf' 3 | android { 4 | compileSdkVersion 29 5 | buildToolsVersion "28.0.3" 6 | defaultConfig { 7 | applicationId "com.projection.car" 8 | minSdkVersion 19 9 | targetSdkVersion 19 10 | versionCode 1 11 | versionName "1.0" 12 | } 13 | buildTypes { 14 | release { 15 | minifyEnabled true 16 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 17 | } 18 | debug { 19 | minifyEnabled false 20 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 21 | } 22 | } 23 | sourceSets { 24 | main { 25 | // 定义proto文件目录 26 | java { 27 | srcDir 'src/main/java' 28 | } 29 | proto { 30 | srcDir 'src/main/proto' 31 | include '**/*.proto' 32 | } 33 | } 34 | } 35 | 36 | lintOptions { 37 | checkReleaseBuilds false 38 | // Or, if you prefer, you can continue to check for errors in release builds, 39 | // but continue the build even when errors are found: 40 | abortOnError false 41 | } 42 | } 43 | 44 | dependencies { 45 | implementation fileTree(dir: 'libs', include: ['*.jar']) 46 | implementation "com.android.support:appcompat-v7:26.1.0" 47 | implementation "com.google.protobuf:protobuf-lite:3.0.0" 48 | // implementation 'com.google.protobuf:protobuf-java:4.0.0-rc-2' 49 | // implementation 'com.google.protobuf:protoc:4.0.0-rc-2' 50 | } 51 | 52 | protobuf { 53 | protoc { 54 | artifact = 'com.google.protobuf:protoc:3.0.0' 55 | } 56 | plugins { 57 | javalite { 58 | artifact = 'com.google.protobuf:protoc-gen-javalite:3.0.0' 59 | } 60 | } 61 | generateProtoTasks { 62 | all().each { task -> 63 | task.plugins { 64 | javalite {} 65 | } 66 | } 67 | } 68 | } 69 | 70 | //protobuf { 71 | // protoc { 72 | // artifact = 'com.google.protobuf:protoc:3.6.1' 73 | // } 74 | // 75 | // generateProtoTasks { 76 | // all().each { task -> 77 | // task.builtins { 78 | // remove java 79 | // } 80 | // task.builtins { 81 | // java {} 82 | // } 83 | // } 84 | // } 85 | //} 86 | 87 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /app/release/app-release.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aa112901/CarProjection/b1ae81117e4baaf809d594fd11af25a0534051fa/app/release/app-release.apk -------------------------------------------------------------------------------- /app/release/output.json: -------------------------------------------------------------------------------- 1 | [{"outputType":{"type":"APK"},"apkInfo":{"type":"MAIN","splits":[],"versionCode":1,"versionName":"1.0","enabled":true,"outputFile":"app-release.apk","fullName":"release","baseName":"release"},"path":"app-release.apk","properties":{}}] -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 24 | 25 | 31 | 32 | 33 | 34 | 37 | 38 | 39 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /app/src/main/assets/app-debug.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aa112901/CarProjection/b1ae81117e4baaf809d594fd11af25a0534051fa/app/src/main/assets/app-debug.apk -------------------------------------------------------------------------------- /app/src/main/java/com/projection/car/ForgroundService.java: -------------------------------------------------------------------------------- 1 | package com.projection.car; 2 | 3 | import android.accessibilityservice.AccessibilityService; 4 | import android.accessibilityservice.AccessibilityServiceInfo; 5 | import android.app.Notification; 6 | import android.app.NotificationChannel; 7 | import android.app.NotificationManager; 8 | import android.content.Context; 9 | import android.content.Intent; 10 | import android.support.v4.app.NotificationCompat; 11 | import android.view.accessibility.AccessibilityEvent; 12 | 13 | import static com.projection.car.Utils.log; 14 | 15 | public class ForgroundService extends AccessibilityService { 16 | 17 | 18 | public static ForgroundService mService; 19 | 20 | AccessibilityServiceInfo info; 21 | 22 | //初始化 23 | @Override 24 | protected void onServiceConnected() { 25 | super.onServiceConnected(); 26 | log("gesture start"); 27 | mService = this; 28 | } 29 | 30 | //实现辅助功能 31 | @Override 32 | public void onAccessibilityEvent(AccessibilityEvent event) { 33 | 34 | 35 | } 36 | 37 | @Override 38 | public void onInterrupt() { 39 | log("gesture onInterrupt"); 40 | mService = null; 41 | } 42 | 43 | @Override 44 | public void onDestroy() { 45 | super.onDestroy(); 46 | log("gesture onDestroy"); 47 | mService = null; 48 | } 49 | 50 | @Override 51 | public void onCreate() { 52 | super.onCreate(); 53 | log("car_projection start"); 54 | 55 | } 56 | 57 | @Override 58 | public int onStartCommand(Intent intent, int flags, int startId) { 59 | if (intent != null && intent.getAction() != null) { 60 | log("action is " + intent.getAction()); 61 | if ("service_start".equals(intent.getAction())) { 62 | NotificationChannel channel = null; 63 | final String channelId = "projection_car"; 64 | if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { 65 | channel = new NotificationChannel(channelId, "System", NotificationManager.IMPORTANCE_LOW); 66 | NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); 67 | if (manager != null) { 68 | manager.createNotificationChannel(channel); 69 | } 70 | } 71 | NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, channelId); 72 | final Notification xiriNotification = notificationBuilder.setOngoing(true) 73 | .setContentText("projection car") 74 | .setWhen(System.currentTimeMillis()) 75 | .setSmallIcon(R.drawable.ic_launcher_background) 76 | .build(); 77 | startForeground(10010, xiriNotification); 78 | } else { 79 | stopForeground(true); 80 | } 81 | 82 | } 83 | return super.onStartCommand(intent, flags, startId); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /app/src/main/java/com/projection/car/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.projection.car; 2 | 3 | import android.app.PendingIntent; 4 | import android.content.BroadcastReceiver; 5 | import android.content.Context; 6 | import android.content.DialogInterface; 7 | import android.content.Intent; 8 | import android.content.IntentFilter; 9 | import android.content.SharedPreferences; 10 | import android.hardware.usb.UsbAccessory; 11 | import android.hardware.usb.UsbManager; 12 | import android.os.Build; 13 | import android.os.Bundle; 14 | import android.os.ParcelFileDescriptor; 15 | import android.os.PowerManager; 16 | import android.provider.Settings; 17 | import android.support.v7.app.AlertDialog; 18 | import android.support.v7.app.AppCompatActivity; 19 | import android.text.TextUtils; 20 | import android.view.View; 21 | import android.widget.EditText; 22 | import android.widget.TextView; 23 | 24 | import java.io.FileDescriptor; 25 | import java.io.FileInputStream; 26 | import java.io.FileOutputStream; 27 | import java.io.IOException; 28 | import java.io.InputStream; 29 | import java.util.ArrayList; 30 | 31 | import static com.projection.car.Utils.REQUEST_CODE; 32 | import static com.projection.car.Utils.getRootAhth; 33 | import static com.projection.car.Utils.log; 34 | import static com.projection.car.Utils.logAll; 35 | import static com.projection.car.Utils.pauseSong; 36 | 37 | public class MainActivity extends AppCompatActivity { 38 | 39 | 40 | private static final String ACTION_USB_PERMISSION = "org.ammlab.android.app.helloadk.action.USB_PERMISSION"; 41 | 42 | 43 | private Context mContext; 44 | 45 | private UsbManager mUsbManager; 46 | private UsbAccessory mUsbAccessory; 47 | private ParcelFileDescriptor mFileDescriptor; 48 | 49 | 50 | private int mVideoBit = 0; 51 | private int mVideoFrame = 0; 52 | 53 | private PowerManager.WakeLock mWakeLock; 54 | 55 | private MsgProcess mMsgProcess; 56 | 57 | 58 | private TextView mLog; 59 | private EditText bitTxt, frameTxt; 60 | private TextView wTxt, hTxt, serialTxt; 61 | 62 | 63 | private BroadcastReceiver mUsbReceiver = new BroadcastReceiver() { 64 | 65 | @Override 66 | public void onReceive(Context context, Intent intent) { 67 | String action = intent.getAction(); 68 | 69 | log("receive accessory_filter connect broadcast:" + action); 70 | 71 | if (ACTION_USB_PERMISSION.equals(action)) { 72 | synchronized (this) { 73 | UsbAccessory accessory = (UsbAccessory) intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY); 74 | 75 | //获取accessory句柄成功 76 | if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) { 77 | log("prepare to open accessory_filter stream"); 78 | 79 | mUsbAccessory = accessory; 80 | openAccessory(mUsbAccessory); 81 | 82 | } else { 83 | log("permission denied for accessory " + accessory); 84 | 85 | mUsbAccessory = null; 86 | 87 | } 88 | } 89 | } else if (UsbManager.ACTION_USB_ACCESSORY_DETACHED.equals(action)) { 90 | 91 | Intent stopintent = new Intent(mContext, ForgroundService.class); 92 | stopintent.setAction("service_stop"); 93 | mContext.startService(stopintent); 94 | 95 | if (mWakeLock.isHeld()) { 96 | mWakeLock.release(); 97 | } 98 | 99 | UsbAccessory accessory = (UsbAccessory) intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY); 100 | log("USB_ACCESSORY_DETACHED " + accessory); 101 | mUsbAccessory = null; 102 | 103 | mMsgProcess.resetUsb(); 104 | 105 | System.exit(0); 106 | 107 | } else if (UsbManager.ACTION_USB_ACCESSORY_ATTACHED.equals(action)) { 108 | UsbAccessory accessory = (UsbAccessory) intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY); 109 | openAccessory(mUsbAccessory); 110 | //检测到us连接 111 | log("USB_ACCESSORY_ATTACHED " + accessory); 112 | } 113 | } 114 | }; 115 | 116 | @Override 117 | protected void onCreate(Bundle savedInstanceState) { 118 | super.onCreate(savedInstanceState); 119 | setContentView(R.layout.activity_main); 120 | mContext = this; 121 | 122 | checkPermission(); 123 | if(!getRootAhth()){ 124 | checkAccessibilitySettingsOn(mContext, ForgroundService.class.getCanonicalName()); 125 | } 126 | 127 | findViewById(R.id.set_plugin1).setOnClickListener(new View.OnClickListener() { 128 | @Override 129 | public void onClick(View v) { 130 | try { 131 | InputStream inputStream = getAssets().open("app-debug.apk"); 132 | byte [] readb = new byte[1024]; 133 | String p = "/sdcard/plugin.apk"; 134 | FileOutputStream fileOutputStream = new FileOutputStream(p); 135 | int len = 0; 136 | while ((len = inputStream.read(readb)) > 0){ 137 | fileOutputStream.write(readb,0,len); 138 | } 139 | if(Utils.installPlugin(p)){ 140 | log("install ok"); 141 | } 142 | 143 | } catch (IOException e) { 144 | e.printStackTrace(); 145 | } 146 | } 147 | }); 148 | 149 | 150 | findViewById(R.id.set_plugin2).setOnClickListener(new View.OnClickListener() { 151 | @Override 152 | public void onClick(View v) { 153 | 154 | } 155 | }); 156 | 157 | findViewById(R.id.delete_plugin).setOnClickListener(new View.OnClickListener() { 158 | @Override 159 | public void onClick(View v) { 160 | Utils.deletPlugin(); 161 | } 162 | }); 163 | 164 | PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); 165 | mWakeLock = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, Utils.TAG); 166 | 167 | 168 | mLog = findViewById(R.id.log); 169 | bitTxt = findViewById(R.id.bit); 170 | frameTxt = findViewById(R.id.frame); 171 | wTxt = findViewById(R.id.w); 172 | hTxt = findViewById(R.id.h); 173 | serialTxt = findViewById(R.id.serial); 174 | 175 | final SharedPreferences sharedPreferences = getSharedPreferences("set", MODE_PRIVATE); 176 | mVideoBit = sharedPreferences.getInt("bit", 30); 177 | mVideoFrame = sharedPreferences.getInt("frame", 3000000); 178 | bitTxt.setText(mVideoBit + ""); 179 | frameTxt.setText(mVideoFrame + ""); 180 | 181 | findViewById(R.id.config).setOnClickListener(new View.OnClickListener() { 182 | @Override 183 | public void onClick(View v) { 184 | String bit = bitTxt.getText().toString(); 185 | String frame = frameTxt.getText().toString(); 186 | sharedPreferences.edit().putInt("bit", Integer.parseInt(bit)).commit(); 187 | sharedPreferences.edit().putInt("frame", Integer.parseInt(frame)).commit(); 188 | Utils.installPlugin(""); 189 | 190 | 191 | } 192 | }); 193 | mMsgProcess = new MsgProcess(this, mVideoBit, mVideoFrame, new MsgProcess.InfoListener() { 194 | @Override 195 | public void onVISSize(int x, int y) { 196 | wTxt.setText("车机屏幕宽度" + x); 197 | hTxt.setText("车机屏幕高度" + y); 198 | } 199 | 200 | @Override 201 | public void onVISID(String id) { 202 | serialTxt.setText("车机id :" + id); 203 | } 204 | }); 205 | 206 | 207 | IntentFilter filter = new IntentFilter(); 208 | filter.addAction(ACTION_USB_PERMISSION); 209 | filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED); 210 | filter.addAction(UsbManager.ACTION_USB_ACCESSORY_ATTACHED); 211 | filter.addAction(UsbManager.ACTION_USB_ACCESSORY_DETACHED); 212 | // filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED); 213 | mContext.registerReceiver(mUsbReceiver, filter); 214 | mUsbManager = (UsbManager) mContext.getSystemService(Context.USB_SERVICE); 215 | 216 | 217 | checkUSBDevice(); 218 | logAll(); 219 | 220 | } 221 | 222 | protected void onActivityResult(int paramInt1, int paramInt2, Intent paramIntent) { 223 | if (paramInt1 == REQUEST_CODE) { 224 | 225 | mMsgProcess.mediaPermissionOk(this, paramInt2, paramIntent); 226 | } 227 | mMsgProcess.startReadAudio(); 228 | } 229 | 230 | 231 | @Override 232 | protected void onDestroy() { 233 | super.onDestroy(); 234 | mContext.unregisterReceiver(mUsbReceiver); 235 | } 236 | 237 | 238 | private void openAccessory(UsbAccessory accessory) { 239 | log("openAccessory"); 240 | mFileDescriptor = mUsbManager.openAccessory(accessory); 241 | 242 | if (mFileDescriptor != null) { 243 | FileDescriptor fd = mFileDescriptor.getFileDescriptor(); 244 | log("now usb fd" + fd); 245 | if (fd != null) { 246 | FileInputStream mInputStream = new FileInputStream(fd); 247 | log("accessory opened DataTranPrepared"); 248 | FileOutputStream mOutputStream = new FileOutputStream(fd); 249 | 250 | mMsgProcess.startProjection(mInputStream, mOutputStream); 251 | 252 | mWakeLock.acquire();//保持屏幕唤醒 253 | 254 | 255 | Intent intent = new Intent(this, ForgroundService.class); 256 | intent.setAction("service_start"); 257 | startService(intent); 258 | } 259 | 260 | log("accessory opened"); 261 | } else { 262 | log("accessory open fail"); 263 | } 264 | } 265 | 266 | private void checkUSBDevice() { 267 | log("checkUSBDevice"); 268 | UsbAccessory[] accessories = mUsbManager.getAccessoryList(); 269 | 270 | if (accessories == null) { 271 | log("accessories list is null"); 272 | return; 273 | } 274 | 275 | log("accessories length " + accessories.length); 276 | 277 | UsbAccessory accessory = accessories[0]; 278 | if (accessory != null) { 279 | log("accessories not null"); 280 | if (mUsbManager.hasPermission(accessory)) { 281 | 282 | mUsbAccessory = accessory; 283 | openAccessory(mUsbAccessory); 284 | } else { 285 | log("accessories null per"); 286 | PendingIntent mPermissionIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ACTION_USB_PERMISSION), 0); 287 | mUsbManager.requestPermission(accessory, mPermissionIntent); 288 | } 289 | } else { 290 | log("accessories null"); 291 | } 292 | } 293 | 294 | 295 | private boolean checkAccessibilitySettingsOn(Context mContext, String serviceName) { 296 | int accessibilityEnabled = 0; 297 | // 对应的服务 298 | final String service = getPackageName() + "/" + serviceName; 299 | try { 300 | accessibilityEnabled = Settings.Secure.getInt(mContext.getApplicationContext().getContentResolver(), 301 | android.provider.Settings.Secure.ACCESSIBILITY_ENABLED); 302 | log("accessibilityEnabled = " + accessibilityEnabled); 303 | } catch (Settings.SettingNotFoundException e) { 304 | log("Error finding setting, default accessibility to not found: " + e.getMessage()); 305 | } 306 | 307 | TextUtils.SimpleStringSplitter mStringColonSplitter = new TextUtils.SimpleStringSplitter(':'); 308 | 309 | if (accessibilityEnabled == 1) { 310 | log("***ACCESSIBILITY IS ENABLED*** -----------------"); 311 | 312 | String settingValue = Settings.Secure.getString(mContext.getApplicationContext().getContentResolver(), 313 | Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES); 314 | if (settingValue != null) { 315 | mStringColonSplitter.setString(settingValue); 316 | while (mStringColonSplitter.hasNext()) { 317 | String accessibilityService = mStringColonSplitter.next(); 318 | log("-------------- > accessibilityService :: " + accessibilityService + " " + service); 319 | if (accessibilityService.equalsIgnoreCase(service)) { 320 | log("We've found the correct setting - accessibility is switched on!"); 321 | return true; 322 | } 323 | } 324 | } 325 | } else { 326 | log("***ACCESSIBILITY IS DISABLED***"); 327 | } 328 | //跳转设置打开无障碍 329 | AlertDialog.Builder builder = new AlertDialog.Builder(mContext, R.style.Theme_AppCompat_DayNight_Dialog); 330 | builder.setTitle("权限申请"); 331 | builder.setMessage("应用需要开启辅助功能,如果取消部分功能不可用"); 332 | builder.setPositiveButton("确定开启", new DialogInterface.OnClickListener() { 333 | @Override 334 | public void onClick(DialogInterface dialog, int which) { 335 | Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS); 336 | startActivity(intent); 337 | } 338 | }); 339 | builder.setNegativeButton("取消", new DialogInterface.OnClickListener() { 340 | @Override 341 | public void onClick(DialogInterface dialog, int which) { 342 | 343 | } 344 | }); 345 | 346 | builder.setCancelable(false); 347 | builder.show(); 348 | 349 | return false; 350 | } 351 | 352 | private void checkPermission() { 353 | if (Build.VERSION.SDK_INT < 21) { 354 | AlertDialog.Builder builder = new AlertDialog.Builder(mContext, R.style.Theme_AppCompat_DayNight_Dialog); 355 | // builder.setTitle("权限申请"); 356 | builder.setMessage("应用需要android 5.1 版本以上运行"); 357 | // builder.setPositiveButton("退出", new DialogInterface.OnClickListener() { 358 | // @Override 359 | // public void onClick(DialogInterface dialog, int which) { 360 | // finish(); 361 | // } 362 | // }); 363 | builder.setNegativeButton("退出", new DialogInterface.OnClickListener() { 364 | @Override 365 | public void onClick(DialogInterface dialog, int which) { 366 | finish(); 367 | } 368 | }); 369 | 370 | builder.setCancelable(false); 371 | builder.show(); 372 | } 373 | 374 | if (Build.VERSION.SDK_INT < 24) { 375 | AlertDialog.Builder builder = new AlertDialog.Builder(mContext, R.style.Theme_AppCompat_DayNight_Dialog); 376 | // builder.setTitle("权限申请"); 377 | builder.setMessage("车机反控功能需要android 7.0版本及以上"); 378 | builder.setPositiveButton("了解", new DialogInterface.OnClickListener() { 379 | @Override 380 | public void onClick(DialogInterface dialog, int which) { 381 | 382 | } 383 | }); 384 | builder.setNegativeButton("退出", new DialogInterface.OnClickListener() { 385 | @Override 386 | public void onClick(DialogInterface dialog, int which) { 387 | finish(); 388 | } 389 | }); 390 | 391 | builder.setCancelable(false); 392 | builder.show(); 393 | } 394 | } 395 | 396 | } 397 | -------------------------------------------------------------------------------- /app/src/main/java/com/projection/car/MediaCodecTool.java: -------------------------------------------------------------------------------- 1 | package com.projection.car; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import android.hardware.display.DisplayManager; 7 | import android.hardware.display.VirtualDisplay; 8 | import android.media.AudioFormat; 9 | import android.media.AudioPlaybackCaptureConfiguration; 10 | import android.media.AudioRecord; 11 | import android.media.MediaCodec; 12 | import android.media.MediaCodecInfo; 13 | import android.media.MediaFormat; 14 | import android.media.MediaRecorder; 15 | import android.media.projection.MediaProjection; 16 | import android.media.projection.MediaProjection.Callback; 17 | import android.media.projection.MediaProjectionManager; 18 | import android.os.Build; 19 | import android.support.annotation.NonNull; 20 | import android.util.Log; 21 | 22 | import java.io.FileNotFoundException; 23 | import java.io.FileOutputStream; 24 | import java.nio.ByteBuffer; 25 | import java.util.Arrays; 26 | 27 | import static com.projection.car.Utils.log; 28 | 29 | 30 | public class MediaCodecTool { 31 | 32 | private static final String SCREENCAP_NAME = "screencap"; 33 | private static final String TAG = MediaCodecTool.class.getName(); 34 | 35 | private MediaProjection sMediaProjection; 36 | private MediaProjectionManager mProjectionManager; 37 | private VirtualDisplay mVirtualDisplay; 38 | 39 | private MediaCodec mMediaCodec; 40 | private boolean mFirstConfigFrame; 41 | private byte[] mConfigByte; 42 | private VideoDataEncodeListener mEncodeCall; 43 | 44 | private int mDensity; 45 | private int mWidth; 46 | private int mHeight; 47 | private int mBit, mFrame; 48 | 49 | private boolean testAudio = false; 50 | private FileOutputStream mOutputStream; 51 | 52 | MediaCodecTool() { 53 | 54 | } 55 | 56 | private void createVirtualDisplay() { 57 | if (testAudio) { 58 | try { 59 | mOutputStream = new FileOutputStream("/sdcard/test.mp4"); 60 | } catch (FileNotFoundException e) { 61 | e.printStackTrace(); 62 | } 63 | } 64 | 65 | 66 | log("VIS w = " + mWidth + ", h = " + mHeight); 67 | try { 68 | mMediaCodec = MediaCodec.createEncoderByType(MediaFormat.MIMETYPE_VIDEO_AVC); 69 | MediaFormat mediaFormat = MediaFormat.createVideoFormat(MediaFormat.MIMETYPE_VIDEO_AVC, mWidth, mHeight); 70 | mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, mFrame);//4000000 71 | mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, mBit);//10 72 | mediaFormat.setInteger(MediaFormat.KEY_CAPTURE_RATE, mBit);//10 73 | mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 1); 74 | mediaFormat.setLong(MediaFormat.KEY_REPEAT_PREVIOUS_FRAME_AFTER, 100000L); 75 | mediaFormat.setLong(MediaFormat.KEY_DURATION, 100000L); 76 | mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface);//2130706433 77 | // mediaFormat.setInteger("profile", 1); 78 | // mediaFormat.setInteger("level", 256); 79 | mMediaCodec.configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE); 80 | 81 | mVirtualDisplay = sMediaProjection.createVirtualDisplay(SCREENCAP_NAME, mWidth, mHeight, mDensity, DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC, mMediaCodec.createInputSurface(), null, null); 82 | 83 | 84 | mMediaCodec.setCallback(new MediaCodec.Callback() { 85 | @Override 86 | public void onInputBufferAvailable(@NonNull MediaCodec codec, int index) { 87 | 88 | } 89 | 90 | @Override 91 | public void onOutputBufferAvailable(@NonNull MediaCodec codec, int index, @NonNull MediaCodec.BufferInfo bufferInfo) { 92 | try { 93 | ByteBuffer outputBuffer = mMediaCodec.getOutputBuffer(index); 94 | byte[] outData = new byte[bufferInfo.size]; 95 | outputBuffer.get(outData); 96 | // flags 利用位操作,定义的 flag 都是 2 的倍数 97 | if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) { // 配置相关的内容,也就是 SPS,PPS 98 | if (testAudio) { 99 | mOutputStream.write(outData, 0, outData.length); 100 | mOutputStream.flush(); 101 | } 102 | 103 | 104 | mConfigByte = new byte[outData.length]; 105 | mFirstConfigFrame = true; 106 | System.arraycopy(outData, 0, mConfigByte, 0, outData.length); 107 | Log.e(TAG, "now CONFIG is" + Arrays.toString(mConfigByte)); 108 | } else if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_KEY_FRAME) != 0) { // 关键帧 109 | if (testAudio) { 110 | mOutputStream.write(outData, 0, outData.length); 111 | mOutputStream.flush(); 112 | } 113 | if (mEncodeCall != null) { 114 | Log.e(TAG, "now frame is" + outData.length); 115 | if (mFirstConfigFrame) { 116 | mFirstConfigFrame = false; 117 | byte[] t = new byte[mConfigByte.length + outData.length]; 118 | System.arraycopy(mConfigByte, 0, t, 0, mConfigByte.length); 119 | System.arraycopy(outData, 0, t, mConfigByte.length, outData.length); 120 | outData = t; 121 | } 122 | 123 | mEncodeCall.onData(outData); 124 | } 125 | } else { 126 | // 非关键帧和SPS、PPS,直接写入文件,可能是B帧或者P帧 127 | if (testAudio) { 128 | mOutputStream.write(outData, 0, outData.length); 129 | mOutputStream.flush(); 130 | } 131 | 132 | if (mEncodeCall != null) { 133 | mEncodeCall.onData(outData); 134 | } 135 | } 136 | mMediaCodec.releaseOutputBuffer(index, false); 137 | } catch (Exception e) { 138 | e.printStackTrace(); 139 | } 140 | 141 | } 142 | 143 | @Override 144 | public void onError(@NonNull MediaCodec codec, @NonNull MediaCodec.CodecException e) { 145 | 146 | } 147 | 148 | @Override 149 | public void onOutputFormatChanged(@NonNull MediaCodec codec, @NonNull MediaFormat format) { 150 | 151 | } 152 | }); 153 | mMediaCodec.start(); 154 | 155 | 156 | // MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo(); 157 | // while (true) { 158 | // int outputBufferIndex = mMediaCodec.dequeueOutputBuffer(bufferInfo, 0); 159 | // // 从输出缓冲区队列中拿到编码好的内容,对内容进行相应处理后在释放 160 | // while (outputBufferIndex >= 0) { 161 | // Log.e(TAG, "outputBufferIndex " + outputBufferIndex); 162 | // ByteBuffer[] outputBuffers = mMediaCodec.getOutputBuffers(); 163 | // ByteBuffer outputBuffer = outputBuffers[outputBufferIndex]; 164 | // byte[] outData = new byte[bufferInfo.size]; 165 | // outputBuffer.get(outData); 166 | // // flags 利用位操作,定义的 flag 都是 2 的倍数 167 | // if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) { // 配置相关的内容,也就是 SPS,PPS 168 | //// mOutputStream.write(outData, 0, outData.length); 169 | //// mOutputStream.flush(); 170 | // 171 | // mConfigByte = new byte[outData.length]; 172 | // mFirstConfigFrame = true; 173 | // System.arraycopy(outData,0,mConfigByte,0,outData.length); 174 | // Log.e(TAG,"now CONFIG is" + Arrays.toString(mConfigByte)); 175 | // } else if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_KEY_FRAME) != 0) { // 关键帧 176 | //// mOutputStream.write(outData, 0, outData.length); 177 | //// mOutputStream.flush(); 178 | // if(mEncodeCall != null){ 179 | // Log.e(TAG,"now frame is" + outData.length); 180 | // if(mFirstConfigFrame){ 181 | // mFirstConfigFrame = false; 182 | // byte[] t = new byte[mConfigByte.length + outData.length]; 183 | // System.arraycopy(mConfigByte,0,t,0,mConfigByte.length); 184 | // System.arraycopy(outData,0,t,mConfigByte.length,outData.length); 185 | // outData = t; 186 | // } 187 | // 188 | // mEncodeCall.onData(outData); 189 | // } 190 | // } else { 191 | // // 非关键帧和SPS、PPS,直接写入文件,可能是B帧或者P帧 192 | //// mOutputStream.write(outData, 0, outData.length); 193 | //// mOutputStream.flush(); 194 | // if(mEncodeCall != null){ 195 | // mEncodeCall.onData(outData); 196 | // } 197 | // } 198 | // mMediaCodec.releaseOutputBuffer(outputBufferIndex, false); 199 | // outputBufferIndex = mMediaCodec.dequeueOutputBuffer(bufferInfo, 0); 200 | // } 201 | // } 202 | 203 | 204 | } catch (Exception localException) { 205 | localException.printStackTrace(); 206 | } 207 | } 208 | 209 | public MediaProjection getMediaProjection(){ 210 | return sMediaProjection; 211 | } 212 | 213 | 214 | public void startProjection(Activity context, VideoDataEncodeListener encodeCall, int code,float w, float h, int bit, int frame) { 215 | mEncodeCall = encodeCall; 216 | mBit = bit; 217 | mFrame = frame; 218 | mWidth = (int) w; 219 | mHeight = (int) h; 220 | mProjectionManager = ((MediaProjectionManager) context.getSystemService(Context.MEDIA_PROJECTION_SERVICE)); 221 | context.startActivityForResult(mProjectionManager.createScreenCaptureIntent(), code); 222 | } 223 | 224 | public void stopProjection() { 225 | if (sMediaProjection != null) { 226 | try { 227 | sMediaProjection.stop(); 228 | } catch (Exception e) { 229 | e.printStackTrace(); 230 | } 231 | } 232 | } 233 | 234 | public void onActivityResult(Activity activity, int paramInt2, Intent paramIntent) { 235 | sMediaProjection = mProjectionManager.getMediaProjection(paramInt2, paramIntent); 236 | if (sMediaProjection != null) { 237 | mDensity = activity.getResources().getDisplayMetrics().densityDpi; 238 | createVirtualDisplay(); 239 | sMediaProjection.registerCallback(new MediaProjectionStopCallback(), null); 240 | } 241 | 242 | } 243 | 244 | 245 | private class MediaProjectionStopCallback extends Callback { 246 | private MediaProjectionStopCallback() { 247 | } 248 | 249 | public void onStop() { 250 | 251 | Log.e(TAG, "stopping projection."); 252 | 253 | mMediaCodec.stop(); 254 | 255 | if (mVirtualDisplay != null) { 256 | mVirtualDisplay.release(); 257 | } 258 | sMediaProjection.unregisterCallback(MediaCodecTool.MediaProjectionStopCallback.this); 259 | } 260 | } 261 | 262 | 263 | public interface VideoDataEncodeListener { 264 | void onData(byte[] data); 265 | } 266 | } 267 | -------------------------------------------------------------------------------- /app/src/main/java/com/projection/car/MsgProcess.java: -------------------------------------------------------------------------------- 1 | package com.projection.car; 2 | 3 | import android.accessibilityservice.AccessibilityService; 4 | import android.accessibilityservice.GestureDescription; 5 | import android.app.Activity; 6 | import android.content.Context; 7 | import android.content.Intent; 8 | import android.content.SharedPreferences; 9 | import android.content.pm.ApplicationInfo; 10 | import android.graphics.Path; 11 | import android.media.AudioAttributes; 12 | import android.media.AudioFormat; 13 | import android.media.AudioPlaybackCaptureConfiguration; 14 | import android.media.AudioRecord; 15 | import android.media.MediaRecorder; 16 | import android.os.Build; 17 | import android.os.Handler; 18 | import android.os.HandlerThread; 19 | import android.os.Looper; 20 | import android.os.Message; 21 | import android.os.SystemClock; 22 | import android.support.annotation.NonNull; 23 | import android.util.DisplayMetrics; 24 | import android.view.Surface; 25 | import android.view.WindowManager; 26 | import android.widget.Toast; 27 | 28 | import com.baidu.carlife.protobuf.CarlifeCarHardKeyCodeProto; 29 | import com.baidu.carlife.protobuf.CarlifeMusicInitProto; 30 | import com.baidu.carlife.protobuf.CarlifeTouchActionProto; 31 | import com.example.car.CarlifeAuthenResultProto; 32 | import com.example.car.CarlifeDeviceInfoProto; 33 | import com.example.car.CarlifeProtocolVersionMatchStatusProto; 34 | import com.example.car.CarlifeStatisticsInfoProto; 35 | import com.example.car.CarlifeVideoEncoderInfoProto; 36 | import com.google.protobuf.InvalidProtocolBufferException; 37 | 38 | import java.io.FileInputStream; 39 | import java.io.FileNotFoundException; 40 | import java.io.FileOutputStream; 41 | import java.io.IOException; 42 | import java.util.ArrayList; 43 | import java.util.Arrays; 44 | 45 | import static android.content.Context.MODE_PRIVATE; 46 | import static com.projection.car.Utils.ACTION_DOWN; 47 | import static com.projection.car.Utils.ACTION_MOVE; 48 | import static com.projection.car.Utils.ACTION_UP; 49 | import static com.projection.car.Utils.CMD; 50 | import static com.projection.car.Utils.KEYCODE_SEEK_ADD; 51 | import static com.projection.car.Utils.KEYCODE_SEEK_SUB; 52 | import static com.projection.car.Utils.MEDIA; 53 | import static com.projection.car.Utils.MSG_CMD_FOREGROUND; 54 | import static com.projection.car.Utils.MSG_CMD_HU_INFO; 55 | import static com.projection.car.Utils.MSG_CMD_HU_PROTOCOL_VERSION; 56 | import static com.projection.car.Utils.MSG_CMD_MD_AUTHEN_RESULT; 57 | import static com.projection.car.Utils.MSG_CMD_MD_INFO; 58 | import static com.projection.car.Utils.MSG_CMD_PROTOCOL_VERSION_MATCH_STATUS; 59 | import static com.projection.car.Utils.MSG_CMD_STATISTIC_INFO; 60 | import static com.projection.car.Utils.MSG_CMD_VIDEO_ENCODER_INIT; 61 | import static com.projection.car.Utils.MSG_CMD_VIDEO_ENCODER_INIT_DONE; 62 | import static com.projection.car.Utils.MSG_CMD_VIDEO_ENCODER_START; 63 | import static com.projection.car.Utils.MSG_MEDIA_DATA; 64 | import static com.projection.car.Utils.MSG_MEDIA_INIT; 65 | import static com.projection.car.Utils.MSG_TOUCH_ACTION; 66 | import static com.projection.car.Utils.MSG_TOUCH_CAR_HARD_KEY_CODE; 67 | import static com.projection.car.Utils.MSG_VIDEO_DATA; 68 | import static com.projection.car.Utils.MSG_WRITE_AUDIO; 69 | import static com.projection.car.Utils.MSG_WRITE_VIDEO; 70 | import static com.projection.car.Utils.REQUEST_CODE; 71 | import static com.projection.car.Utils.TOUCH; 72 | import static com.projection.car.Utils.VIDEO; 73 | import static com.projection.car.Utils.bytesToInt2; 74 | import static com.projection.car.Utils.bytesToShort2; 75 | import static com.projection.car.Utils.exportCMDMsg; 76 | import static com.projection.car.Utils.exportVideoMsg; 77 | import static com.projection.car.Utils.intToBytes2; 78 | import static com.projection.car.Utils.log; 79 | import static com.projection.car.Utils.nextSong; 80 | import static com.projection.car.Utils.previosSong; 81 | 82 | public class MsgProcess { 83 | 84 | private boolean testAduio = false; 85 | 86 | 87 | private volatile boolean usbOk; 88 | private FileInputStream mInputStream; 89 | private FileOutputStream mOutputStream; 90 | private Activity mContext; 91 | 92 | 93 | private Handler mUsbReadHandler; 94 | private Handler mUsbWriteHandler; 95 | 96 | 97 | private AudioHandler mAudioReadHandler; 98 | 99 | private MediaCodecTool mMediaCodecTool; 100 | 101 | private Path mGesturePath = new Path(); 102 | private int mGestureMoveCount = 0; 103 | private ArrayList mGestureMoveArray = new ArrayList<>(); 104 | private long mGestureStartTime = 0; 105 | 106 | private float mVISWidth = 1280; 107 | private float mVISHeight = 720; 108 | private float mMobileWidth = 1920; 109 | private float mMobileHeight = 1080; 110 | private float mPortraitScreenVISGestureFactorW = 1.0f; 111 | private float mPortraitScreenVISGestureFactorH = 1.0f; 112 | private float mLandscapeScreenVISGestureFactorW = 1.0f; 113 | private float mLandscapeScreenVISGestureFactorH = 1.0f; 114 | 115 | private float mLeft_x; 116 | private Handler mMainHandler = new Handler(); 117 | 118 | private int mVideoBit = 0; 119 | private int mVideoFrame = 0; 120 | private InfoListener mInfoListener; 121 | 122 | MsgProcess(Activity context, int bit, int frame, InfoListener infoListener) { 123 | 124 | mContext = context; 125 | mInfoListener = infoListener; 126 | mVideoBit = bit; 127 | mVideoFrame = frame; 128 | 129 | refreshSize(); 130 | 131 | mMediaCodecTool = new MediaCodecTool(); 132 | 133 | HandlerThread audioThread = new HandlerThread("audio"); 134 | audioThread.start(); 135 | mAudioReadHandler = new AudioHandler(audioThread.getLooper()); 136 | 137 | 138 | startUsbTransferThread(); 139 | 140 | if (testAduio) { 141 | mMediaCodecTool.startProjection(mContext, videoDataEncodeListener, REQUEST_CODE, mVISWidth, mVISHeight, mVideoBit, mVideoFrame); 142 | mAudioReadHandler.sendEmptyMessage(AudioHandler.AUDIO_START); 143 | } 144 | } 145 | 146 | private Runnable runnable = new Runnable() { 147 | @Override 148 | public void run() { 149 | 150 | mInputStream = null; 151 | mOutputStream = null; 152 | } 153 | }; 154 | 155 | private Runnable runnable_toast = new Runnable() { 156 | @Override 157 | public void run() { 158 | 159 | Toast.makeText(mContext, "当前版本未授权,稍后自动断连", Toast.LENGTH_LONG).show(); 160 | } 161 | }; 162 | 163 | public void startProjection(FileInputStream in, FileOutputStream out) { 164 | log("startProjection"); 165 | usbOk = true; 166 | mInputStream = in; 167 | mOutputStream = out; 168 | mUsbReadHandler.sendEmptyMessage(0); 169 | 170 | } 171 | 172 | public void mediaPermissionOk(Activity activity, int paramInt2, Intent paramIntent) { 173 | mMediaCodecTool.onActivityResult(activity, paramInt2, paramIntent); 174 | } 175 | 176 | public synchronized void resetUsb() { 177 | if (usbOk) { 178 | log("resetUsb"); 179 | usbOk = false; 180 | mAudioReadHandler.sendEmptyMessage(AudioHandler.AUDIO_STOP); 181 | mMediaCodecTool.stopProjection(); 182 | mUsbWriteHandler.removeCallbacksAndMessages(null); 183 | } 184 | 185 | } 186 | 187 | public void startReadAudio() { 188 | mAudioReadHandler.sendEmptyMessage(AudioHandler.AUDIO_START); 189 | } 190 | 191 | 192 | private MediaCodecTool.VideoDataEncodeListener videoDataEncodeListener = new MediaCodecTool.VideoDataEncodeListener() { 193 | @Override 194 | public void onData(byte[] data) { 195 | try { 196 | // log("data len = " + data.length); 197 | byte[] carLifeMsg = exportVideoMsg(MSG_VIDEO_DATA, data); 198 | byte[] headmsg = new byte[8]; 199 | headmsg[3] = VIDEO; 200 | intToBytes2(carLifeMsg.length, headmsg, 4);//carlifemsg len 201 | CarMsg carMsg = new CarMsg(headmsg, carLifeMsg); 202 | mUsbWriteHandler.obtainMessage(MSG_WRITE_VIDEO, carMsg).sendToTarget(); 203 | } catch (Exception e) { 204 | e.printStackTrace(); 205 | } 206 | 207 | } 208 | }; 209 | 210 | private void refreshSize() { 211 | 212 | mMainHandler.post(new Runnable() { 213 | @Override 214 | public void run() { 215 | mInfoListener.onVISSize((int) mVISWidth, (int) mVISHeight); 216 | 217 | } 218 | }); 219 | 220 | 221 | DisplayMetrics metrics = new DisplayMetrics(); 222 | WindowManager manager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); 223 | manager.getDefaultDisplay().getRealMetrics(metrics); 224 | log("www = " + metrics.widthPixels + " hhh = " + metrics.heightPixels); 225 | mMobileWidth = metrics.widthPixels; 226 | mMobileHeight = metrics.heightPixels; 227 | final SharedPreferences sharedPreferences = mContext.getSharedPreferences("set", MODE_PRIVATE); 228 | mMobileWidth = sharedPreferences.getFloat("mobile_w", (float) mMobileWidth); 229 | mMobileHeight = sharedPreferences.getFloat("mobile_h", (float) mMobileHeight); 230 | mLandscapeScreenVISGestureFactorW = mMobileWidth / mVISWidth; 231 | mLandscapeScreenVISGestureFactorH = mMobileHeight / mVISHeight; 232 | 233 | float portrixScrennWidth = mVISWidth * mVISHeight / mMobileWidth;// 车机竖屏的实际宽 用车机的高做投屏的高,保持比例 234 | mPortraitScreenVISGestureFactorW = mMobileHeight / (portrixScrennWidth);//竖屏下宽带除车机投屏实际屏幕宽度 235 | mPortraitScreenVISGestureFactorH = mMobileWidth / mVISHeight; 236 | 237 | mLeft_x = (mVISWidth - portrixScrennWidth) / 2.0f; //界面偏移值 238 | log("refreshSize w " + mMobileWidth + " h = " + mMobileHeight + ", mVISWidth " + mVISWidth + "mVISHeight" + mVISHeight + ", mirror = " + mPortraitScreenVISGestureFactorW + ", " + mPortraitScreenVISGestureFactorH + 239 | mLandscapeScreenVISGestureFactorW + ", " + mLandscapeScreenVISGestureFactorH + ", leftx " + mLeft_x); 240 | } 241 | 242 | private void genarateGesture(int type, float g_x, float g_y) { 243 | float x = 0; 244 | float y = 0; 245 | if (type == ACTION_DOWN) { 246 | mGestureStartTime = SystemClock.elapsedRealtime(); 247 | mGesturePath.reset(); 248 | mGestureMoveArray.clear(); 249 | mGestureMoveCount = 0; 250 | int angle = ((WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getRotation(); 251 | 252 | if (angle == Surface.ROTATION_0) { 253 | x = (g_x - mLeft_x) * mPortraitScreenVISGestureFactorW; 254 | y = g_y * mPortraitScreenVISGestureFactorH; 255 | 256 | } else if (angle == Surface.ROTATION_90) { 257 | x = g_x * mLandscapeScreenVISGestureFactorW; 258 | y = g_y * mLandscapeScreenVISGestureFactorH; 259 | } 260 | log("now moveTo x = " + x + ", " + y); 261 | mGesturePath.moveTo(x, y); 262 | mGestureMoveArray.add(x); 263 | mGestureMoveArray.add(y); 264 | 265 | } else if (type == ACTION_UP) { 266 | 267 | long gestureTime = 30; 268 | if (mGestureMoveCount > 2) { 269 | gestureTime = SystemClock.elapsedRealtime() - mGestureStartTime; 270 | gestureTime = gestureTime > 300 ? 300 : gestureTime; 271 | } 272 | 273 | log("now dispatchGesture time is " + gestureTime); 274 | 275 | Utils.touch(mGestureMoveArray, gestureTime); 276 | 277 | GestureDescription.StrokeDescription sd = new GestureDescription.StrokeDescription(mGesturePath, 0, gestureTime); 278 | 279 | if (ForgroundService.mService != null) { 280 | ForgroundService.mService.dispatchGesture(new GestureDescription.Builder().addStroke(sd).build(), new AccessibilityService.GestureResultCallback() { 281 | @Override 282 | public void onCompleted(GestureDescription gestureDescription) { 283 | super.onCompleted(gestureDescription); 284 | log("now dispatchGesture ok"); 285 | } 286 | 287 | @Override 288 | public void onCancelled(GestureDescription gestureDescription) { 289 | super.onCancelled(gestureDescription); 290 | log("now dispatchGesture cancle"); 291 | } 292 | }, null); 293 | } 294 | } else if (type == ACTION_MOVE) { 295 | int angle = ((WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getRotation(); 296 | if (angle == Surface.ROTATION_0 || angle == Surface.ROTATION_180) { 297 | x = (g_x - mLeft_x) * mPortraitScreenVISGestureFactorW; 298 | y = g_y * mPortraitScreenVISGestureFactorH; 299 | 300 | } else if (angle == Surface.ROTATION_90 || angle == Surface.ROTATION_270) { 301 | x = g_x * mLandscapeScreenVISGestureFactorW; 302 | y = g_y * mLandscapeScreenVISGestureFactorH; 303 | } 304 | log("now lineTo x = " + x + ", " + y); 305 | mGesturePath.lineTo(x, y); 306 | mGestureMoveArray.add(x); 307 | mGestureMoveArray.add(y); 308 | mGestureMoveCount++; 309 | } 310 | 311 | } 312 | 313 | 314 | class AudioHandler extends Handler { 315 | 316 | public static final int AUDIO_START = 0; 317 | public static final int AUDIO_READ = 1; 318 | public static final int AUDIO_STOP = 3; 319 | 320 | private AudioRecord mAudioRecord; 321 | private boolean mAudioStart; 322 | private FileOutputStream fileOutputStream; 323 | 324 | 325 | public AudioHandler(Looper looper) { 326 | super(looper); 327 | } 328 | 329 | @Override 330 | public void handleMessage(@NonNull Message msg) { 331 | super.handleMessage(msg); 332 | switch (msg.what) { 333 | case AUDIO_START: 334 | try { 335 | if (mAudioStart) { 336 | break; 337 | } 338 | if (testAduio) { 339 | try { 340 | fileOutputStream = new FileOutputStream("/sdcard/remix.pcm"); 341 | } catch (FileNotFoundException e) { 342 | e.printStackTrace(); 343 | } 344 | } 345 | int sample = 48000; 346 | 347 | // if(!(isSystemApp(mContext) || isSystemUpdateApp(mContext)) && Build.VERSION.SDK_INT >= 29) { 348 | 349 | if (Build.VERSION.SDK_INT >= 23) { 350 | 351 | try { 352 | AudioPlaybackCaptureConfiguration config = new AudioPlaybackCaptureConfiguration.Builder(mMediaCodecTool.getMediaProjection()) 353 | .excludeUsage(AudioAttributes.USAGE_NOTIFICATION) 354 | .build(); 355 | int minBufferSize = AudioRecord.getMinBufferSize(sample, AudioFormat.CHANNEL_IN_STEREO, AudioFormat.ENCODING_PCM_16BIT); 356 | mAudioRecord = new AudioRecord.Builder() 357 | .setAudioPlaybackCaptureConfig(config) 358 | .setAudioFormat(new AudioFormat.Builder() 359 | .setEncoding(AudioFormat.ENCODING_PCM_16BIT) 360 | .setSampleRate(sample) 361 | .setChannelMask(AudioFormat.CHANNEL_IN_STEREO) 362 | .build()) 363 | .setBufferSizeInBytes(minBufferSize) 364 | .build(); 365 | } catch (Exception e) { 366 | e.printStackTrace(); 367 | } 368 | 369 | } else { 370 | int minBufferSize = AudioRecord.getMinBufferSize(sample, AudioFormat.CHANNEL_IN_STEREO, AudioFormat.ENCODING_PCM_16BIT); 371 | mAudioRecord = new AudioRecord(MediaRecorder.AudioSource.REMOTE_SUBMIX, sample, AudioFormat.CHANNEL_IN_STEREO, AudioFormat.ENCODING_PCM_16BIT, minBufferSize); 372 | 373 | } 374 | 375 | mAudioRecord.startRecording(); 376 | mAudioStart = true; 377 | mAudioReadHandler.sendEmptyMessage(AUDIO_READ); 378 | } catch (Exception e) { 379 | e.printStackTrace(); 380 | mAudioStart = false; 381 | } 382 | 383 | break; 384 | case AUDIO_READ: 385 | if (mAudioStart) { 386 | byte[] data = new byte[2560]; 387 | int len = 0; 388 | try { 389 | len = mAudioRecord.read(data, 0, data.length); 390 | if (!testAduio) { 391 | byte[] carLifeMsg = exportVideoMsg(MSG_MEDIA_DATA, data, len); 392 | byte[] headmsg = new byte[8]; 393 | headmsg[3] = MEDIA; 394 | intToBytes2(carLifeMsg.length, headmsg, 4);//carlifemsg len 395 | CarMsg carMsg = new CarMsg(headmsg, carLifeMsg); 396 | mUsbWriteHandler.obtainMessage(MSG_WRITE_AUDIO, carMsg).sendToTarget(); 397 | } 398 | 399 | mAudioReadHandler.sendEmptyMessage(AUDIO_READ); 400 | 401 | } catch (Exception e) { 402 | e.printStackTrace(); 403 | mAudioStart = false; 404 | } 405 | 406 | if (testAduio) { 407 | try { 408 | fileOutputStream.write(data, 0, len); 409 | } catch (IOException e) { 410 | e.printStackTrace(); 411 | } 412 | } 413 | } 414 | 415 | break; 416 | case AUDIO_STOP: 417 | try { 418 | if (mAudioStart) { 419 | mAudioRecord.stop(); 420 | mAudioStart = false; 421 | } 422 | 423 | } catch (Exception e) { 424 | e.printStackTrace(); 425 | mAudioStart = false; 426 | } 427 | break; 428 | } 429 | 430 | } 431 | } 432 | 433 | private void startUsbTransferThread() { 434 | HandlerThread inthread = new HandlerThread("read"); 435 | inthread.start(); 436 | mUsbReadHandler = new Handler(inthread.getLooper()) { 437 | @Override 438 | public void handleMessage(@NonNull Message msg) { 439 | super.handleMessage(msg); 440 | switch (msg.what) { 441 | case 0: { 442 | // mMainHandler.postDelayed(runnable_toast,300000 - 3000); 443 | // mMainHandler.postDelayed(runnable,300000); 444 | while (usbOk) { 445 | try { 446 | byte[] data = new byte[8]; 447 | int len = mInputStream.read(data); 448 | 449 | if (len == 8) { 450 | int msg_type = data[3]; 451 | log("msg_type = " + msg_type + ", read data = " + Arrays.toString(data)); 452 | int msgLen = bytesToInt2(data, 4); 453 | log("msgLen = " + msgLen); 454 | byte[] msgdata = new byte[msgLen]; 455 | len = mInputStream.read(msgdata); 456 | log("read data = " + Arrays.toString(msgdata)); 457 | log("read msg data = " + len + " msgLen " + msgLen); 458 | short carmsgLen = bytesToShort2(msgdata, 0); 459 | int type = bytesToInt2(msgdata, 4); 460 | log("read carmsgLen data = " + carmsgLen + " type " + type); 461 | byte[] carmsg = new byte[carmsgLen]; 462 | System.arraycopy(msgdata, 8, carmsg, 0, carmsgLen); 463 | msgdata = carmsg; 464 | if (msg_type == CMD) { 465 | switch (type) { 466 | case MSG_CMD_HU_PROTOCOL_VERSION: { 467 | CarlifeProtocolVersionMatchStatusProto.CarlifeProtocolVersionMatchStatus.Builder builder = CarlifeProtocolVersionMatchStatusProto.CarlifeProtocolVersionMatchStatus.newBuilder(); 468 | builder.setMatchStatus(1); 469 | byte[] result = builder.build().toByteArray(); 470 | log(" match = " + Arrays.toString(result)); 471 | mUsbWriteHandler.obtainMessage(MSG_CMD_PROTOCOL_VERSION_MATCH_STATUS, exportCMDMsg(MSG_CMD_PROTOCOL_VERSION_MATCH_STATUS, result)).sendToTarget(); 472 | } 473 | break; 474 | case MSG_CMD_HU_INFO: { 475 | try { 476 | final CarlifeDeviceInfoProto.CarlifeDeviceInfo deviceInfo = CarlifeDeviceInfoProto.CarlifeDeviceInfo.parseFrom(msgdata); 477 | log("os =" + deviceInfo.getOs() + ", cid =" + deviceInfo.getCid() + ", serial =" + deviceInfo.getSerial()); 478 | 479 | 480 | } catch (InvalidProtocolBufferException e) { 481 | e.printStackTrace(); 482 | } 483 | 484 | CarlifeDeviceInfoProto.CarlifeDeviceInfo.Builder builder = CarlifeDeviceInfoProto.CarlifeDeviceInfo.newBuilder(); 485 | builder.setSdkInt(29); 486 | builder.setSdk("29"); 487 | builder.setSerial("unknown"); 488 | builder.setCid("QKQ1.190828.002"); 489 | builder.setBoard("sdm845"); 490 | builder.setOs("Android"); 491 | builder.setRelease("10"); 492 | builder.setHost("c4-miui-ota-bd47.bj"); 493 | mUsbWriteHandler.obtainMessage(MSG_CMD_MD_INFO, exportCMDMsg(MSG_CMD_MD_INFO, builder.build().toByteArray())).sendToTarget(); 494 | } 495 | break; 496 | case MSG_CMD_VIDEO_ENCODER_INIT: { 497 | try { 498 | CarlifeVideoEncoderInfoProto.CarlifeVideoEncoderInfo encoderInfo = CarlifeVideoEncoderInfoProto.CarlifeVideoEncoderInfo.parseFrom(msgdata); 499 | log("encoderInfo = " + encoderInfo.getWidth() + ", " + encoderInfo.getHeight() + ", " + encoderInfo.getFrameRate()); 500 | if (encoderInfo.getWidth() > 10 && encoderInfo.getHeight() > 10) { 501 | mVISWidth = encoderInfo.getWidth(); 502 | mVISHeight = encoderInfo.getHeight(); 503 | refreshSize(); 504 | log("get cheji MirrorWidth = " + mVISWidth + ", MirrorHeight" + mVISHeight); 505 | } 506 | 507 | } catch (InvalidProtocolBufferException e) { 508 | e.printStackTrace(); 509 | } 510 | 511 | CarlifeVideoEncoderInfoProto.CarlifeVideoEncoderInfo.Builder builder = CarlifeVideoEncoderInfoProto.CarlifeVideoEncoderInfo.newBuilder(); 512 | builder.setFrameRate(mVideoBit); 513 | builder.setWidth((int) mVISWidth); 514 | builder.setHeight((int) mVISHeight); 515 | mUsbWriteHandler.obtainMessage(MSG_CMD_VIDEO_ENCODER_INIT_DONE, exportCMDMsg(MSG_CMD_VIDEO_ENCODER_INIT_DONE, msgdata)).sendToTarget(); 516 | 517 | 518 | } 519 | break; 520 | case MSG_CMD_VIDEO_ENCODER_START: { 521 | mUsbWriteHandler.obtainMessage(MSG_CMD_VIDEO_ENCODER_START).sendToTarget(); 522 | } 523 | break; 524 | case MSG_CMD_STATISTIC_INFO: { 525 | 526 | try { 527 | final CarlifeStatisticsInfoProto.CarlifeStatisticsInfo statisticsInfo = CarlifeStatisticsInfoProto.CarlifeStatisticsInfo.parseFrom(msgdata); 528 | log("getCuid = " + statisticsInfo.getCuid() + "" + statisticsInfo.getVersionName() + statisticsInfo.getConnectTime() + statisticsInfo.getCrashLog()); 529 | mMainHandler.post(new Runnable() { 530 | @Override 531 | public void run() { 532 | mInfoListener.onVISID(statisticsInfo.getCuid()); 533 | } 534 | }); 535 | } catch (InvalidProtocolBufferException e) { 536 | e.printStackTrace(); 537 | } 538 | CarlifeAuthenResultProto.CarlifeAuthenResult.Builder builder = CarlifeAuthenResultProto.CarlifeAuthenResult.newBuilder(); 539 | builder.setResult(true); 540 | mUsbWriteHandler.obtainMessage(MSG_CMD_MD_AUTHEN_RESULT, exportCMDMsg(MSG_CMD_MD_AUTHEN_RESULT, builder.build().toByteArray())).sendToTarget(); 541 | } 542 | break; 543 | 544 | 545 | } 546 | } else if (msg_type == TOUCH) { 547 | log("read TOUCH data = " + Arrays.toString(msgdata)); 548 | switch (type) { 549 | case MSG_TOUCH_CAR_HARD_KEY_CODE: { 550 | CarlifeCarHardKeyCodeProto.CarlifeCarHardKeyCode keyCode = CarlifeCarHardKeyCodeProto.CarlifeCarHardKeyCode.parseFrom(msgdata); 551 | log("keycode = " + keyCode.getKeycode()); 552 | switch (keyCode.getKeycode()) { 553 | case KEYCODE_SEEK_SUB: { 554 | previosSong(); 555 | } 556 | break; 557 | case KEYCODE_SEEK_ADD: { 558 | nextSong(); 559 | } 560 | break; 561 | } 562 | 563 | } 564 | break; 565 | case MSG_TOUCH_ACTION: { 566 | try { 567 | CarlifeTouchActionProto.CarlifeTouchAction action = CarlifeTouchActionProto.CarlifeTouchAction.parseFrom(msgdata); 568 | genarateGesture(action.getAction(), action.getX(), action.getY()); 569 | log("encoderInfo = " + action.getX() + ", " + action.getY() + ", " + action.getAction()); 570 | } catch (Exception e) { 571 | e.printStackTrace(); 572 | } 573 | } 574 | break; 575 | } 576 | 577 | 578 | } 579 | 580 | 581 | } else { 582 | log("read data = " + len + " " + data.length); 583 | } 584 | 585 | } catch (Exception e) { 586 | e.printStackTrace(); 587 | 588 | resetUsb(); 589 | break; 590 | } 591 | 592 | //SystemClock.sleep(10); 593 | } 594 | } 595 | } 596 | } 597 | }; 598 | 599 | HandlerThread outthread = new HandlerThread("write"); 600 | outthread.start(); 601 | mUsbWriteHandler = new Handler(outthread.getLooper()) { 602 | @Override 603 | public void handleMessage(@NonNull Message msg) { 604 | super.handleMessage(msg); 605 | 606 | try { 607 | switch (msg.what) { 608 | case MSG_CMD_PROTOCOL_VERSION_MATCH_STATUS: 609 | case MSG_CMD_MD_INFO: 610 | case MSG_CMD_MD_AUTHEN_RESULT: { 611 | byte[] carLifeMsg = (byte[]) msg.obj; 612 | byte[] headmsg = new byte[8]; 613 | headmsg[3] = CMD; 614 | intToBytes2(carLifeMsg.length, headmsg, 4);//carlifemsg len 615 | mOutputStream.write(headmsg); 616 | log("msg=" + msg.what + "write data =" + Arrays.toString(headmsg)); 617 | mOutputStream.write(carLifeMsg); 618 | log("msg=" + msg.what + "write data =" + Arrays.toString(carLifeMsg)); 619 | log("write data ok"); 620 | } 621 | break; 622 | case MSG_CMD_VIDEO_ENCODER_INIT_DONE: { 623 | 624 | { 625 | byte[] carLifeMsg = (byte[]) msg.obj; 626 | byte[] headmsg = new byte[8]; 627 | headmsg[3] = CMD; 628 | intToBytes2(carLifeMsg.length, headmsg, 4);//carlifemsg len 629 | mOutputStream.write(headmsg); 630 | log("msg=" + msg.what + "write data =" + Arrays.toString(headmsg)); 631 | mOutputStream.write(carLifeMsg); 632 | log("msg=" + msg.what + "write data =" + Arrays.toString(carLifeMsg)); 633 | log("write data ok"); 634 | } 635 | 636 | { 637 | byte[] carLifeMsg = exportCMDMsg(MSG_CMD_FOREGROUND, null); 638 | byte[] headmsg = new byte[8]; 639 | headmsg[3] = CMD; 640 | intToBytes2(carLifeMsg.length, headmsg, 4);//carlifemsg len 641 | mOutputStream.write(headmsg); 642 | log("msg=" + MSG_CMD_FOREGROUND + "write data =" + Arrays.toString(headmsg)); 643 | mOutputStream.write(carLifeMsg); 644 | log("msg=" + MSG_CMD_FOREGROUND + "write data =" + Arrays.toString(carLifeMsg)); 645 | log("write data ok"); 646 | } 647 | 648 | 649 | } 650 | break; 651 | case MSG_CMD_VIDEO_ENCODER_START: { 652 | log("now start MSG_CMD_VIDEO_ENCODER_START"); 653 | 654 | CarlifeMusicInitProto.CarlifeMusicInit.Builder builder = CarlifeMusicInitProto.CarlifeMusicInit.newBuilder(); 655 | builder.setSampleRate(48000); 656 | builder.setChannelConfig(2); 657 | builder.setSampleFormat(16); 658 | byte[] carLifeMsg = exportVideoMsg(MSG_MEDIA_INIT, builder.build().toByteArray()); 659 | byte[] headmsg = new byte[8]; 660 | headmsg[3] = MEDIA; 661 | intToBytes2(carLifeMsg.length, headmsg, 4);//carlifemsg len 662 | mOutputStream.write(headmsg); 663 | log("msg=MSG_MEDIA_INIT" + "write data =" + Arrays.toString(headmsg)); 664 | mOutputStream.write(carLifeMsg); 665 | log("msg=MSG_MEDIA_INIT" + "write data =" + Arrays.toString(carLifeMsg)); 666 | log("write data ok audiohandler start"); 667 | 668 | //mAudioReadHandler.sendEmptyMessage(AudioHandler.AUDIO_START); 669 | mMediaCodecTool.startProjection(mContext, videoDataEncodeListener, REQUEST_CODE, mVISWidth, mVISHeight, mVideoBit, mVideoFrame); 670 | } 671 | break; 672 | case MSG_WRITE_AUDIO: 673 | case MSG_WRITE_VIDEO: { 674 | //log("write audio or video ..................." + msg.what); 675 | CarMsg carMsg = (CarMsg) msg.obj; 676 | mOutputStream.write(carMsg.head); 677 | mOutputStream.write(carMsg.msg); 678 | } 679 | break; 680 | } 681 | } catch (Exception e) { 682 | e.printStackTrace(); 683 | resetUsb(); 684 | } 685 | } 686 | }; 687 | } 688 | 689 | public boolean isSystemApp(Context context) { 690 | return ((context.getApplicationInfo().flags & ApplicationInfo.FLAG_SYSTEM) != 0); 691 | } 692 | 693 | public boolean isSystemUpdateApp(Context context) { 694 | return ((context.getApplicationInfo().flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0); 695 | } 696 | 697 | public interface InfoListener { 698 | void onVISSize(int x, int y); 699 | 700 | void onVISID(String id); 701 | } 702 | 703 | static class CarMsg { 704 | byte[] head; 705 | byte[] msg; 706 | 707 | CarMsg(byte[] b1, byte[] b3) { 708 | head = b1; 709 | msg = b3; 710 | } 711 | } 712 | } 713 | -------------------------------------------------------------------------------- /app/src/main/java/com/projection/car/Utils.java: -------------------------------------------------------------------------------- 1 | package com.projection.car; 2 | 3 | import android.util.Log; 4 | 5 | import java.io.BufferedReader; 6 | import java.io.DataOutputStream; 7 | import java.io.File; 8 | import java.io.FileOutputStream; 9 | import java.io.IOException; 10 | import java.io.InputStreamReader; 11 | import java.util.ArrayList; 12 | 13 | public class Utils { 14 | 15 | public final static String TAG = "CarProjection"; 16 | 17 | public static final int REQUEST_CODE = 100; 18 | 19 | public static final byte CMD = 1; 20 | public static final byte VIDEO = 2; 21 | public static final byte MEDIA = 3; 22 | public static final byte TOUCH = 6; 23 | 24 | public static final int ACTION_DOWN = 0; 25 | public static final int ACTION_UP = 1; 26 | public static final int ACTION_MOVE = 2; 27 | 28 | 29 | public static final int MSG_WRITE_AUDIO = 10; 30 | 31 | public static final int MSG_WRITE_VIDEO = 11; 32 | 33 | public static final int MSG_CMD_HU_PROTOCOL_VERSION = 0x00018001;//98305 34 | public static final int MSG_CMD_HU_INFO = 0x00018003;//98307 35 | public static final int MSG_CMD_VIDEO_ENCODER_INIT = 0x00018007;//98311 36 | public static final int MSG_CMD_VIDEO_ENCODER_START = 0x00018009;//98313 37 | public static final int MSG_CMD_STATISTIC_INFO = 0x00018027;//98343 38 | 39 | 40 | public static final int MSG_CMD_PROTOCOL_VERSION_MATCH_STATUS = 0x00010002;//65538 41 | public static final int MSG_CMD_MD_INFO = 0x00010004;//65540 42 | public static final int MSG_CMD_SCREEN_ON = 0x00010018;//65560 43 | public static final int MSG_CMD_VIDEO_ENCODER_INIT_DONE = 0x00010008;//65544 44 | public static final int MSG_CMD_MD_AUTHEN_RESULT = 0x0001004B;//65611 45 | public static final int MSG_CMD_FOREGROUND = 0x0001001B;//65563 46 | 47 | 48 | public static final int MSG_CMD_MD_FEATURE_CONFIG_REQUEST = 0x00010051;//65617 49 | public static final int MSG_CMD_HU_FEATURE_CONFIG_RESPONSE = 0x00018052;//98386 50 | 51 | 52 | // Media通道相关消息 53 | public static final int MSG_MEDIA_INIT = 0x00030001; 54 | public static final int MSG_MEDIA_STOP = 0x00030002; 55 | public static final int MSG_MEDIA_PAUSE = 0x00030003; 56 | public static final int MSG_MEDIA_RESUME_PLAY = 0x00030004; 57 | public static final int MSG_MEDIA_SEEK_TO = 0x00030005; 58 | public static final int MSG_MEDIA_DATA = 0x00030006; 59 | 60 | public static final int MSG_VIDEO_DATA = 0x00020001; 61 | 62 | 63 | // Touch通道相关消息 64 | public static final int MSG_TOUCH_ACTION = 0x00068001; 65 | public static final int MSG_TOUCH_ACTION_DOWN = 0x00068002; 66 | public static final int MSG_TOUCH_ACTION_UP = 0x00068003; 67 | public static final int MSG_TOUCH_ACTION_MOVE = 0x00068004; 68 | public static final int MSG_TOUCH_SINGLE_CLICK = 0x00068005; 69 | public static final int MSG_TOUCH_DOUBLE_CLICK = 0x00068006; 70 | public static final int MSG_TOUCH_LONG_PRESS = 0x00068007; 71 | public static final int MSG_TOUCH_CAR_HARD_KEY_CODE = 0x00068008; 72 | public static final int MSG_TOUCH_UI_ACTION_SOUND = 0x00060009; 73 | public static final int MSG_TOUCH_ACTION_BEGIN = 0x0006800A; 74 | 75 | 76 | // 硬按键消息 77 | public static final int KEYCODE_HOME = 0x00000001; 78 | public static final int KEYCODE_PHONE_CALL = 0x00000002; 79 | public static final int KEYCODE_PHONE_END = 0x00000003; 80 | public static final int KEYCODE_PHONE_END_MUTE = 0x00000004; 81 | public static final int KEYCODE_HFP = 0x00000005; 82 | public static final int KEYCODE_SELECTOR_NEXT = 0x00000006; 83 | public static final int KEYCODE_SELECTOR_PREVIOUS = 0x00000007; 84 | public static final int KEYCODE_SETTING = 0x00000008; 85 | public static final int KEYCODE_MEDIA = 0x00000009; 86 | public static final int KEYCODE_RADIO = 0x0000000A; 87 | public static final int KEYCODE_NAVI = 0x0000000B; 88 | public static final int KEYCODE_SRC = 0x0000000C; 89 | public static final int KEYCODE_MODE = 0x0000000D; 90 | public static final int KEYCODE_BACK = 0x0000000E; 91 | public static final int KEYCODE_SEEK_SUB = 0x0000000F; 92 | public static final int KEYCODE_SEEK_ADD = 0x00000010; 93 | public static final int KEYCODE_VOLUME_SUB = 0x00000011; 94 | public static final int KEYCODE_VOLUME_ADD = 0x00000012; 95 | public static final int KEYCODE_MUTE = 0x00000013; 96 | public static final int KEYCODE_OK = 0x00000014; 97 | public static final int KEYCODE_MOVE_LEFT = 0x00000015; 98 | public static final int KEYCODE_MOVE_RIGHT = 0x00000016; 99 | public static final int KEYCODE_MOVE_UP = 0x00000017; 100 | public static final int KEYCODE_MOVE_DOWN = 0x00000018; 101 | public static final int KEYCODE_MOVE_UP_LEFT = 0x00000019; 102 | public static final int KEYCODE_MOVE_UP_RIGHT = 0x0000001A; 103 | public static final int KEYCODE_MOVE_DOWN_LEFT = 0x0000001B; 104 | public static final int KEYCODE_MOVE_DOWN_RIGHT = 0x0000001C; 105 | public static final int KEYCODE_TEL = 0x0000001D; 106 | public static final int KEYCODE_MAIN = 0x0000001E; 107 | public static final int KEYCODE_MEDIA_START = 0x0000001F; 108 | public static final int KEYCODE_MEDIA_STOP = 0x00000020; 109 | public static final int KEYCODE_VR_START = 0x00000021; 110 | public static final int KEYCODE_VR_STOP = 0x00000022; 111 | public static final int KEYCODE_NUMBER_0 = 0x00000023; 112 | public static final int KEYCODE_NUMBER_1 = 0x00000024; 113 | public static final int KEYCODE_NUMBER_2 = 0x00000025; 114 | public static final int KEYCODE_NUMBER_3 = 0x00000026; 115 | public static final int KEYCODE_NUMBER_4 = 0x00000027; 116 | public static final int KEYCODE_NUMBER_5 = 0x00000028; 117 | public static final int KEYCODE_NUMBER_6 = 0x00000029; 118 | public static final int KEYCODE_NUMBER_7 = 0x0000002A; 119 | public static final int KEYCODE_NUMBER_8 = 0x0000002B; 120 | public static final int KEYCODE_NUMBER_9 = 0x0000002C; 121 | public static final int KEYCODE_NUMBER_STAR = 0x0000002D; // * 122 | public static final int KEYCODE_NUMBER_POUND = 0x0000002E; // # 123 | public static final int KEYCODE_NUMBER_DEL = 0x0000002F; 124 | public static final int KEYCODE_NUMBER_CLEAR = 0x00000030; 125 | public static final int KEYCODE_NUMBER_ADD = 0x00000031; // + 126 | 127 | public static byte[] exportCMDMsg(int service, byte[] result) { 128 | byte[] carlife = null; 129 | if (result == null) { 130 | carlife = new byte[8]; 131 | shortToBytes((short) 0, carlife, 0);// data len 132 | intToBytes2(service, carlife, 4); 133 | } else { 134 | carlife = new byte[8 + result.length]; 135 | shortToBytes((short) result.length, carlife, 0);// data len 136 | intToBytes2(service, carlife, 4); 137 | System.arraycopy(result, 0, carlife, 8, result.length); 138 | } 139 | 140 | return carlife; 141 | } 142 | 143 | 144 | public static byte[] exportVideoMsg(int service, byte[] result, int len) { 145 | byte[] carlife = null; 146 | carlife = new byte[12 + len]; 147 | intToBytes2(len, carlife, 0);// data len 148 | //Log.e(TAG, "time = " + (int) (System.currentTimeMillis())); 149 | intToBytes2((int) (System.currentTimeMillis()), carlife, 4); 150 | intToBytes2(service, carlife, 8); 151 | System.arraycopy(result, 0, carlife, 12, len); 152 | 153 | return carlife; 154 | } 155 | 156 | public static byte[] exportVideoMsg(int service, byte[] result) { 157 | byte[] carlife = null; 158 | carlife = new byte[12 + result.length]; 159 | intToBytes2(result.length, carlife, 0);// data len 160 | //Log.e(TAG, "time = " + (int) (System.currentTimeMillis())); 161 | intToBytes2((int) (System.currentTimeMillis()), carlife, 4); 162 | intToBytes2(service, carlife, 8); 163 | System.arraycopy(result, 0, carlife, 12, result.length); 164 | 165 | return carlife; 166 | } 167 | 168 | public static int getPCMPackageHeadTimeStamp(byte[] mPCMPacakgeHeadBuffer) { 169 | int timeStamp; 170 | int dataHH = (mPCMPacakgeHeadBuffer[4] & 0xff); 171 | int dataHL = (mPCMPacakgeHeadBuffer[5] & 0xff); 172 | int dataLH = (mPCMPacakgeHeadBuffer[6] & 0xff); 173 | int dataLL = (mPCMPacakgeHeadBuffer[7] & 0xff); 174 | 175 | timeStamp = 176 | ((dataHH << 24) & 0xff000000) | ((dataHL << 16) & 0x00ff0000) | ((dataLH << 8) & 0x0000ff00) 177 | | ((dataLL) & 0x000000ff); 178 | 179 | return timeStamp; 180 | } 181 | 182 | public static short bytesToShort2(byte[] src, int offset) { 183 | short value; 184 | value = (short) (((src[offset] & 0xFF) << 8) 185 | | (src[offset + 1] & 0xFF)); 186 | return value; 187 | } 188 | 189 | public static int bytesToInt2(byte[] src, int offset) { 190 | int value; 191 | value = (int) (((src[offset] & 0xFF) << 24) 192 | | ((src[offset + 1] & 0xFF) << 16) 193 | | ((src[offset + 2] & 0xFF) << 8) 194 | | (src[offset + 3] & 0xFF)); 195 | return value; 196 | } 197 | 198 | // * 将int数值转换为占四个字节的byte数组,本方法适用于(高位在前,低位在后)的顺序。 和bytesToInt2()配套使用 199 | public static byte[] intToBytes2(int value) { 200 | byte[] src = new byte[4]; 201 | src[0] = (byte) ((value >> 24) & 0xFF); 202 | src[1] = (byte) ((value >> 16) & 0xFF); 203 | src[2] = (byte) ((value >> 8) & 0xFF); 204 | src[3] = (byte) (value & 0xFF); 205 | return src; 206 | } 207 | 208 | public static byte[] intToBytes2(int value, byte[] src, int offset) { 209 | 210 | src[offset] = (byte) ((value >> 24) & 0xFF); 211 | src[offset + 1] = (byte) ((value >> 16) & 0xFF); 212 | src[offset + 2] = (byte) ((value >> 8) & 0xFF); 213 | src[offset + 3] = (byte) (value & 0xFF); 214 | return src; 215 | } 216 | 217 | public static byte[] shortToBytes(short value) { 218 | byte[] src = new byte[2]; 219 | src[0] = (byte) ((value >> 8) & 0xFF); 220 | src[1] = (byte) (value & 0xFF); 221 | return src; 222 | } 223 | 224 | public static byte[] shortToBytes(short value, byte[] src, int offset) { 225 | src[offset] = (byte) ((value >> 8) & 0xFF); 226 | src[offset + 1] = (byte) (value & 0xFF); 227 | return src; 228 | } 229 | 230 | public static void logAll() { 231 | new Thread(new Runnable() { 232 | 233 | @Override 234 | public void run() { 235 | android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_BACKGROUND); 236 | Process logcatProcess = null; 237 | BufferedReader bufferedReader = null; 238 | try { 239 | // 获取系统logcat日志信息 240 | String[] running = new String[]{"logcat", "-v", 241 | "time"}; 242 | logcatProcess = Runtime.getRuntime().exec(running); 243 | bufferedReader = new BufferedReader( 244 | new InputStreamReader(logcatProcess 245 | .getInputStream())); 246 | StringBuilder logString = new StringBuilder(); 247 | String line; 248 | File file = new File("/sdcard/log"); 249 | if (file.length() > 1024 * 1024 * 10) { 250 | file.delete(); 251 | file = new File("/sdcard/log"); 252 | } 253 | FileOutputStream outputStream = new FileOutputStream(file, true); 254 | while ((line = bufferedReader.readLine()) != null) { 255 | logString.append(" ").append(line).append("\n"); 256 | // MyLog.logD(TAG, line); 257 | outputStream.write((line + "\n").getBytes()); 258 | } 259 | } catch (Exception e) { 260 | e.printStackTrace(); 261 | } 262 | } 263 | }).start(); 264 | } 265 | 266 | public static boolean reboot(){ 267 | try { 268 | 269 | os.writeBytes("reboot\n"); 270 | os.flush(); 271 | } catch (IOException e) { 272 | e.printStackTrace(); 273 | return false; 274 | } 275 | 276 | return true; 277 | } 278 | 279 | public static void root() { 280 | try { 281 | Process process = Runtime.getRuntime().exec("su"); 282 | DataOutputStream os = new DataOutputStream(process.getOutputStream()); 283 | os.writeBytes("busybox mount -o remount,rw /system\n"); 284 | os.writeBytes("cat /sdcard/log > /system/priv-app/log\n"); 285 | os.writeBytes("busybox mount -o remount,ro /system\n"); 286 | os.writeBytes("exit\n"); 287 | os.flush(); 288 | } catch (IOException e) { 289 | e.printStackTrace(); 290 | } 291 | } 292 | 293 | public static boolean installPlugin(String str) { 294 | try { 295 | // Process process = Runtime.getRuntime().exec("su"); 296 | // DataOutputStream os = new DataOutputStream(process.getOutputStream()); 297 | os.writeBytes("cat -r " + str + "> /system/priv-app/Projection/projection.apk\n"); 298 | os.writeBytes("busybox mount -o remount,rw /system\n"); 299 | os.writeBytes("rm -r /system/priv-app/projection.apk\n"); 300 | os.writeBytes("cat -r " + str + "> /system/priv-app/projection.apk\n"); 301 | os.writeBytes("busybox mount -o remount,ro /system\n"); 302 | os.writeBytes("rm " + str + "\n"); 303 | // os.writeBytes("exit\n"); 304 | os.flush(); 305 | } catch (IOException e) { 306 | e.printStackTrace(); 307 | return false; 308 | } 309 | 310 | return true; 311 | } 312 | 313 | public static boolean deletPlugin() { 314 | try { 315 | os.writeBytes("rm -r /system/priv-app/projection.apk\n"); 316 | os.flush(); 317 | } catch (IOException e) { 318 | e.printStackTrace(); 319 | return false; 320 | } 321 | 322 | return true; 323 | } 324 | 325 | public static void nextSong() { 326 | try { 327 | // Process process = Runtime.getRuntime().exec("su"); 328 | // DataOutputStream os = new DataOutputStream(process.getOutputStream()); 329 | os.writeBytes("input keyevent 87\n"); 330 | // os.writeBytes("exit\n"); 331 | os.flush(); 332 | } catch (IOException e) { 333 | e.printStackTrace(); 334 | } 335 | } 336 | 337 | public static void pauseSong() { 338 | try { 339 | // Process process = Runtime.getRuntime().exec("su"); 340 | // DataOutputStream os = new DataOutputStream(process.getOutputStream()); 341 | os.writeBytes("input keyevent 85"); 342 | // os.writeBytes("exit\n"); 343 | os.flush(); 344 | } catch (IOException e) { 345 | e.printStackTrace(); 346 | } 347 | } 348 | 349 | public static void stopSong() { 350 | try { 351 | // Process process = Runtime.getRuntime().exec("su"); 352 | // DataOutputStream os = new DataOutputStream(process.getOutputStream()); 353 | os.writeBytes("input keyevent 86"); 354 | // os.writeBytes("exit\n"); 355 | os.flush(); 356 | } catch (IOException e) { 357 | e.printStackTrace(); 358 | } 359 | } 360 | 361 | public static void previosSong() { 362 | try { 363 | // Process process = Runtime.getRuntime().exec("su"); 364 | // DataOutputStream os = new DataOutputStream(process.getOutputStream()); 365 | os.writeBytes("input keyevent 88 \n"); 366 | // os.writeBytes("exit\n"); 367 | os.flush(); 368 | } catch (IOException e) { 369 | e.printStackTrace(); 370 | } 371 | } 372 | 373 | private static DataOutputStream os; 374 | 375 | public static void touch(ArrayList list, long time) { 376 | try { 377 | String command = "\n"; 378 | if (list.size() == 2) { 379 | command = "input touchscreen tap " + list.get(0) + " " + list.get(1) + "\n"; 380 | } else { 381 | command = "input touchscreen swipe " + list.get(0) + " " + list.get(1) + " " + 382 | list.get(list.size() - 2) + " " + list.get(list.size() - 1) + " " + time + "\n"; 383 | } 384 | 385 | 386 | if (os == null) { 387 | Process process = Runtime.getRuntime().exec("su"); 388 | os = new DataOutputStream(process.getOutputStream()); 389 | 390 | } 391 | os.writeBytes(command); 392 | os.flush(); 393 | } catch (IOException e) { 394 | e.printStackTrace(); 395 | } 396 | } 397 | 398 | 399 | public static synchronized boolean getRootAhth() { 400 | try { 401 | if (os == null) { 402 | Process process = Runtime.getRuntime().exec("su"); 403 | os = new DataOutputStream(process.getOutputStream()); 404 | 405 | } 406 | } catch (IOException e) { 407 | e.printStackTrace(); 408 | return false; 409 | } 410 | 411 | return true; 412 | } 413 | 414 | public static void log(String str) { 415 | Log.e(TAG, str); 416 | } 417 | 418 | } 419 | -------------------------------------------------------------------------------- /app/src/main/proto/CarlifeAccelerationProto.proto: -------------------------------------------------------------------------------- 1 | package com.baidu.carlife.protobuf; 2 | message CarlifeAcceleration 3 | { 4 | required double accX = 1; 5 | required double accY = 2; 6 | required double accZ = 3; 7 | optional uint64 timeStamp = 4; 8 | } 9 | -------------------------------------------------------------------------------- /app/src/main/proto/CarlifeAuthenRequestProto.proto: -------------------------------------------------------------------------------- 1 | package com.baidu.carlife.protobuf; 2 | message CarlifeAuthenRequest 3 | { 4 | required string randomValue = 1; 5 | } 6 | -------------------------------------------------------------------------------- /app/src/main/proto/CarlifeAuthenResponseProto.proto: -------------------------------------------------------------------------------- 1 | package com.baidu.carlife.protobuf; 2 | message CarlifeAuthenResponse 3 | { 4 | required string encryptValue = 1; 5 | } 6 | -------------------------------------------------------------------------------- /app/src/main/proto/CarlifeAuthenResultProto.proto: -------------------------------------------------------------------------------- 1 | 2 | package com.example.car; 3 | option java_outer_classname = "CarlifeAuthenResultProto"; 4 | message CarlifeAuthenResult 5 | { 6 | required bool result = 1; 7 | } -------------------------------------------------------------------------------- /app/src/main/proto/CarlifeBTHfpConnectionProto.proto: -------------------------------------------------------------------------------- 1 | package com.baidu.carlife.protobuf; 2 | message CarlifeBTHfpConnection 3 | { 4 | required int32 state = 1; 5 | optional string address = 2; 6 | optional string name = 3; 7 | } 8 | -------------------------------------------------------------------------------- /app/src/main/proto/CarlifeBTHfpIndicationProto.proto: -------------------------------------------------------------------------------- 1 | package com.baidu.carlife.protobuf; 2 | message CarlifeBTHfpIndication 3 | { 4 | required int32 state = 1; 5 | optional string phoneNum = 2; 6 | optional string phoneName = 3; 7 | optional string address=4; 8 | } 9 | -------------------------------------------------------------------------------- /app/src/main/proto/CarlifeBTHfpRequestProto.proto: -------------------------------------------------------------------------------- 1 | package com.baidu.carlife.protobuf; 2 | message CarlifeBTHfpRequest 3 | { 4 | required int32 command = 1; 5 | optional string phoneNum = 2; 6 | optional int32 dtmfCode = 3; 7 | } 8 | -------------------------------------------------------------------------------- /app/src/main/proto/CarlifeBTHfpResponseProto.proto: -------------------------------------------------------------------------------- 1 | package com.baidu.carlife.protobuf; 2 | message CarlifeBTHfpResponse 3 | { 4 | required int32 status = 1; 5 | required int32 cmd = 2; 6 | optional int32 dtmfCode = 3; 7 | } 8 | -------------------------------------------------------------------------------- /app/src/main/proto/CarlifeBTHfpStatusRequestProto.proto: -------------------------------------------------------------------------------- 1 | package com.baidu.carlife.protobuf; 2 | message CarlifeBTHfpStatusRequest 3 | { 4 | required int32 type = 1; 5 | } 6 | -------------------------------------------------------------------------------- /app/src/main/proto/CarlifeBTHfpStatusResponseProto.proto: -------------------------------------------------------------------------------- 1 | package com.baidu.carlife.protobuf; 2 | message CarlifeBTHfpStatusResponse 3 | { 4 | required int32 status = 1; 5 | required int32 type = 2; 6 | } 7 | -------------------------------------------------------------------------------- /app/src/main/proto/CarlifeBTIdentifyResultIndProto.proto: -------------------------------------------------------------------------------- 1 | package com.baidu.carlife.protobuf; 2 | message CarlifeBTIdentifyResultInd 3 | { 4 | required int32 status = 1; 5 | required string address = 2; 6 | } 7 | -------------------------------------------------------------------------------- /app/src/main/proto/CarlifeBTPairInfoProto.proto: -------------------------------------------------------------------------------- 1 | package com.baidu.carlife.protobuf; 2 | message CarlifeBTPairInfo 3 | { 4 | required string address = 1; 5 | optional string passKey = 2; 6 | optional string hash = 3; 7 | optional string randomizer = 4; 8 | required string uuid = 5; 9 | required string name = 6; 10 | required int32 status = 7; 11 | } -------------------------------------------------------------------------------- /app/src/main/proto/CarlifeBTStartIdentifyReqProto.proto: -------------------------------------------------------------------------------- 1 | package com.baidu.carlife.protobuf; 2 | message CarlifeBTStartIdentifyReq 3 | { 4 | required string address = 1; 5 | } 6 | -------------------------------------------------------------------------------- /app/src/main/proto/CarlifeBTStartPairReqProto.proto: -------------------------------------------------------------------------------- 1 | package com.baidu.carlife.protobuf; 2 | message CarlifeBTStartPairReq 3 | { 4 | required int32 ostype = 1; 5 | optional string address = 2; 6 | } 7 | -------------------------------------------------------------------------------- /app/src/main/proto/CarlifeCallRecordsListProto.proto: -------------------------------------------------------------------------------- 1 | package com.baidu.carlife.protobuf; 2 | import "CarlifeCallRecordsProto.proto"; 3 | message CarlifeCallRecordsList 4 | { 5 | required int32 cnt = 1; 6 | repeated com.baidu.carlife.protobuf.CarlifeCallRecords carlifeCallRecords = 2; 7 | } 8 | -------------------------------------------------------------------------------- /app/src/main/proto/CarlifeCallRecordsProto.proto: -------------------------------------------------------------------------------- 1 | package com.baidu.carlife.protobuf; 2 | message CarlifeCallRecords 3 | { 4 | required int32 cid = 1; 5 | required string name = 2; 6 | required string number = 3; 7 | required string duration = 4; 8 | required string time = 5; 9 | 10 | enum CallRecordsType 11 | { 12 | DEFAULT_TYPE = 0; 13 | INCOMING_TYPE = 1; 14 | OUTGOING_TYPE = 2; 15 | MISSED_TYPE = 3; 16 | } 17 | 18 | required CallRecordsType type = 6 [default = DEFAULT_TYPE]; 19 | } 20 | -------------------------------------------------------------------------------- /app/src/main/proto/CarlifeCarGpsProto.proto: -------------------------------------------------------------------------------- 1 | package com.baidu.carlife.protobuf; 2 | message CarlifeCarGps 3 | { 4 | required uint32 antennaState = 1; 5 | required uint32 signalQuality = 2; 6 | required int32 latitude = 3; 7 | required int32 longitude = 4; 8 | required int32 height = 5; 9 | required uint32 speed = 6; 10 | required uint32 heading = 7; 11 | required uint32 year = 8; 12 | required uint32 month = 9; 13 | required uint32 day = 10; 14 | required uint32 hrs = 11; 15 | required uint32 min = 12; 16 | required uint32 sec = 13; 17 | required uint32 fix = 14; 18 | required uint32 hdop = 15; 19 | required uint32 pdop = 16; 20 | required uint32 vdop = 17; 21 | required uint32 satsUsed = 18; 22 | required uint32 satsVisible = 19; 23 | required uint32 horPosError = 20; 24 | required uint32 vertPosError = 21; 25 | required int32 northSpeed = 22; 26 | required int32 eastSpeed = 23; 27 | required int32 vertSpeed = 24; 28 | optional uint64 timeStamp = 25; 29 | } 30 | -------------------------------------------------------------------------------- /app/src/main/proto/CarlifeCarHardKeyCodeProto.proto: -------------------------------------------------------------------------------- 1 | package com.baidu.carlife.protobuf; 2 | message CarlifeCarHardKeyCode 3 | { 4 | required int32 keycode = 1; 5 | } 6 | -------------------------------------------------------------------------------- /app/src/main/proto/CarlifeCarSpeedProto.proto: -------------------------------------------------------------------------------- 1 | package com.baidu.carlife.protobuf; 2 | message CarlifeCarSpeed 3 | { 4 | required int32 speed = 1; 5 | optional uint64 timeStamp = 2; 6 | } 7 | -------------------------------------------------------------------------------- /app/src/main/proto/CarlifeConnectExceptionProto.proto: -------------------------------------------------------------------------------- 1 | package com.baidu.carlife.protobuf; 2 | message CarlifeConnectException 3 | { 4 | required int32 exceptionType = 1; 5 | } 6 | -------------------------------------------------------------------------------- /app/src/main/proto/CarlifeContactsListProto.proto: -------------------------------------------------------------------------------- 1 | package com.baidu.carlife.protobuf; 2 | import "CarlifeContactsProto.proto"; 3 | message CarlifeContactsList 4 | { 5 | required int32 cnt = 1; 6 | repeated com.baidu.carlife.protobuf.CarlifeContacts carlifeContacts = 2; 7 | } 8 | -------------------------------------------------------------------------------- /app/src/main/proto/CarlifeContactsProto.proto: -------------------------------------------------------------------------------- 1 | package com.baidu.carlife.protobuf; 2 | message CarlifeContacts 3 | { 4 | required int32 cid = 1; 5 | required string name = 2; 6 | required string number = 3; 7 | } 8 | -------------------------------------------------------------------------------- /app/src/main/proto/CarlifeDeviceInfoProto.proto: -------------------------------------------------------------------------------- 1 | 2 | package com.example.car; 3 | option java_outer_classname = "CarlifeDeviceInfoProto"; 4 | message CarlifeDeviceInfo 5 | { 6 | optional string os = 1; 7 | optional string board = 2; 8 | optional string bootloader = 3; 9 | optional string brand = 4; 10 | optional string cpu_abi = 5; 11 | optional string cpu_abi2 = 6; 12 | optional string device =7; 13 | optional string display = 8; 14 | optional string fingerprint = 9; 15 | optional string hardware = 10; 16 | optional string host = 11; 17 | optional string cid = 12; 18 | optional string manufacturer = 13; 19 | optional string model = 14; 20 | optional string product = 15; 21 | optional string serial = 16; 22 | optional string codename = 17; 23 | optional string incremental = 18; 24 | optional string release = 19; 25 | optional string sdk = 20; 26 | optional int32 sdk_int = 21; 27 | optional string token = 22; 28 | optional string btaddress = 23; 29 | optional string btname = 24; 30 | } -------------------------------------------------------------------------------- /app/src/main/proto/CarlifeErrorCodeProto.proto: -------------------------------------------------------------------------------- 1 | package com.baidu.carlife.protobuf; 2 | message CarlifeErrorCode 3 | { 4 | required string errorCode = 1; 5 | } 6 | -------------------------------------------------------------------------------- /app/src/main/proto/CarlifeFeatureConfigListProto.proto: -------------------------------------------------------------------------------- 1 | package com.baidu.carlife.protobuf; 2 | import "CarlifeFeatureConfigProto.proto"; 3 | message CarlifeFeatureConfigList 4 | { 5 | required int32 cnt = 1; 6 | repeated com.baidu.carlife.protobuf.CarlifeFeatureConfig featureConfig = 2; 7 | } -------------------------------------------------------------------------------- /app/src/main/proto/CarlifeFeatureConfigProto.proto: -------------------------------------------------------------------------------- 1 | package com.baidu.carlife.protobuf; 2 | message CarlifeFeatureConfig 3 | { 4 | required string key = 1; 5 | required int32 value = 2; 6 | } -------------------------------------------------------------------------------- /app/src/main/proto/CarlifeGearInfoProto.proto: -------------------------------------------------------------------------------- 1 | package com.baidu.carlife.protobuf; 2 | message CarlifeGearInfo 3 | { 4 | required int32 gear = 1; 5 | } -------------------------------------------------------------------------------- /app/src/main/proto/CarlifeGyroscopeProto.proto: -------------------------------------------------------------------------------- 1 | package com.baidu.carlife.protobuf; 2 | message CarlifeGyroscope 3 | { 4 | required int32 gyroType = 1; 5 | required double gyroX = 2; 6 | required double gyroy = 3; 7 | required double gyroZ = 4; 8 | optional uint64 timeStamp = 5; 9 | } 10 | -------------------------------------------------------------------------------- /app/src/main/proto/CarlifeMediaInfoListProto.proto: -------------------------------------------------------------------------------- 1 | package com.baidu.carlife.protobuf; 2 | import "CarlifeMediaInfoProto.proto"; 3 | message CarlifeMediaInfoList 4 | { 5 | required int32 cnt = 1; 6 | repeated com.baidu.carlife.protobuf.CarlifeMediaInfo mediaInfo = 2; 7 | } 8 | -------------------------------------------------------------------------------- /app/src/main/proto/CarlifeMediaInfoProto.proto: -------------------------------------------------------------------------------- 1 | package com.baidu.carlife.protobuf; 2 | message CarlifeMediaInfo 3 | { 4 | required string source = 1; 5 | required string song = 2; 6 | required string artist = 3; 7 | required string album = 4; 8 | required bytes albumArt = 5; 9 | required int32 duration = 6; 10 | required int32 playlistNum = 7; 11 | required string songId = 8; 12 | required int32 mode = 9; 13 | } 14 | -------------------------------------------------------------------------------- /app/src/main/proto/CarlifeMediaProgressBarProto.proto: -------------------------------------------------------------------------------- 1 | package com.baidu.carlife.protobuf; 2 | message CarlifeMediaProgressBar 3 | { 4 | required int32 progressBar = 1; 5 | } 6 | -------------------------------------------------------------------------------- /app/src/main/proto/CarlifeModuleStatusListProto.proto: -------------------------------------------------------------------------------- 1 | package com.baidu.carlife.protobuf; 2 | import "CarlifeModuleStatusProto.proto"; 3 | message CarlifeModuleStatusList 4 | { 5 | required int32 cnt = 1; 6 | repeated com.baidu.carlife.protobuf.CarlifeModuleStatus moduleStatus = 2; 7 | } 8 | -------------------------------------------------------------------------------- /app/src/main/proto/CarlifeModuleStatusProto.proto: -------------------------------------------------------------------------------- 1 | package com.baidu.carlife.protobuf; 2 | message CarlifeModuleStatus 3 | { 4 | required int32 moduleID = 1; 5 | required int32 statusID = 2; 6 | } 7 | -------------------------------------------------------------------------------- /app/src/main/proto/CarlifeMusicInitProto.proto: -------------------------------------------------------------------------------- 1 | package com.baidu.carlife.protobuf; 2 | message CarlifeMusicInit 3 | { 4 | required int32 sampleRate = 1; 5 | required int32 channelConfig = 2; 6 | required int32 sampleFormat = 3; 7 | } 8 | -------------------------------------------------------------------------------- /app/src/main/proto/CarlifeNaviAssitantGuideInfoProto.proto: -------------------------------------------------------------------------------- 1 | package com.baidu.carlife.protobuf; 2 | message CarlifeNaviAssitantGuideInfo 3 | { 4 | required int32 action = 1; 5 | required int32 assistantType = 2; 6 | required int32 trafficSignType=3; 7 | required int32 totalDistance=4; 8 | required int32 remainDistance=5; 9 | required int32 cameraSpeed=6; 10 | } -------------------------------------------------------------------------------- /app/src/main/proto/CarlifeNaviNextTurnInfoProto.proto: -------------------------------------------------------------------------------- 1 | package com.baidu.carlife.protobuf; 2 | message CarlifeNaviNextTurnInfo 3 | { 4 | required int32 action=1; 5 | required int32 nextTurn=2; 6 | required string roadName=3; 7 | required int32 totalDistance=4; 8 | required int32 remainDistance=5; 9 | required int32 time=6; 10 | } -------------------------------------------------------------------------------- /app/src/main/proto/CarlifeOilProto.proto: -------------------------------------------------------------------------------- 1 | package com.baidu.carlife.protobuf; 2 | message CarlifeOil 3 | { 4 | required int32 level = 1; 5 | required int32 range = 2; 6 | optional bool lowFuleWarning = 3; 7 | } 8 | -------------------------------------------------------------------------------- /app/src/main/proto/CarlifeProtocolVersionMatchStatusProto.proto: -------------------------------------------------------------------------------- 1 | 2 | package com.example.car; 3 | option java_outer_classname = "CarlifeProtocolVersionMatchStatusProto"; 4 | message CarlifeProtocolVersionMatchStatus 5 | { 6 | required int32 matchStatus = 1; 7 | } -------------------------------------------------------------------------------- /app/src/main/proto/CarlifeProtocolVersionProto.proto: -------------------------------------------------------------------------------- 1 | 2 | package com.example.car; 3 | option java_outer_classname = "CarlifeProtocolVersionProto"; 4 | message CarlifeProtocolVersion 5 | { 6 | required int32 majorVersion = 1; 7 | required int32 minorVersion = 2; 8 | } -------------------------------------------------------------------------------- /app/src/main/proto/CarlifeStatisticsInfoProto.proto: -------------------------------------------------------------------------------- 1 | 2 | package com.example.car; 3 | option java_outer_classname = "CarlifeStatisticsInfoProto"; 4 | message CarlifeStatisticsInfo 5 | { 6 | required string cuid = 1; 7 | required string versionName = 2; 8 | required int32 versionCode = 3; 9 | required string channel = 4; 10 | required int32 connectCount = 5; 11 | required int32 connectSuccessCount = 6; 12 | required int32 connectTime = 7; 13 | optional string crashLog = 8; 14 | } -------------------------------------------------------------------------------- /app/src/main/proto/CarlifeSubscribeMobileCarLifeInfoListProto.proto: -------------------------------------------------------------------------------- 1 | package com.baidu.carlife.protobuf; 2 | import "CarlifeSubscribeMobileCarLifeInfoProto.proto"; 3 | message CarlifeSubscribeMobileCarLifeInfoList 4 | { 5 | required int32 cnt = 1; 6 | repeated CarlifeSubscribeMobileCarLifeInfo subscribemobileCarLifeInfo = 2; 7 | } -------------------------------------------------------------------------------- /app/src/main/proto/CarlifeSubscribeMobileCarLifeInfoProto.proto: -------------------------------------------------------------------------------- 1 | package com.baidu.carlife.protobuf; 2 | message CarlifeSubscribeMobileCarLifeInfo 3 | { 4 | required int32 moduleID = 1; 5 | optional bool supportFlag = 2; 6 | optional int32 frequency=3; 7 | } -------------------------------------------------------------------------------- /app/src/main/proto/CarlifeTTSInitProto.proto: -------------------------------------------------------------------------------- 1 | package com.baidu.carlife.protobuf; 2 | message CarlifeTTSInit 3 | { 4 | required int32 sampleRate = 1; 5 | required int32 channelConfig = 2; 6 | required int32 sampleFormat = 3; 7 | } 8 | -------------------------------------------------------------------------------- /app/src/main/proto/CarlifeTouchActionProto.proto: -------------------------------------------------------------------------------- 1 | package com.baidu.carlife.protobuf; 2 | message CarlifeTouchAction 3 | { 4 | required int32 action = 1; 5 | required int32 x = 2; 6 | required int32 y = 3; 7 | } 8 | -------------------------------------------------------------------------------- /app/src/main/proto/CarlifeTouchEventAllDeviceProto.proto: -------------------------------------------------------------------------------- 1 | package com.baidu.carlife.protobuf; 2 | import "CarlifeTouchEventDeviceProto.proto"; 3 | message CarlifeTouchEventAllDevice 4 | { 5 | required int32 version = 1; 6 | required int32 cnt = 2; 7 | repeated com.baidu.carlife.protobuf.CarlifeTouchEventDevice devices = 3; 8 | } 9 | -------------------------------------------------------------------------------- /app/src/main/proto/CarlifeTouchEventDeviceProto.proto: -------------------------------------------------------------------------------- 1 | package com.baidu.carlife.protobuf; 2 | import "CarlifeTouchEventProto.proto"; 3 | message CarlifeTouchEventDevice 4 | { 5 | required int32 cid = 1; 6 | required int32 eventx = 2; 7 | required int32 screen_width = 3; 8 | required int32 screen_height = 4; 9 | required int32 abs_x_min = 5; 10 | required int32 abs_x_max = 6; 11 | required int32 abs_y_min = 7; 12 | required int32 abs_y_max = 8; 13 | required string device = 9; 14 | repeated com.baidu.carlife.protobuf.CarlifeTouchEvent downEvent = 10; 15 | repeated com.baidu.carlife.protobuf.CarlifeTouchEvent upEvent = 11; 16 | repeated com.baidu.carlife.protobuf.CarlifeTouchEvent moveEvent = 12; 17 | } 18 | -------------------------------------------------------------------------------- /app/src/main/proto/CarlifeTouchEventProto.proto: -------------------------------------------------------------------------------- 1 | package com.baidu.carlife.protobuf; 2 | message CarlifeTouchEvent 3 | { 4 | required int32 type = 1; 5 | required int32 code = 2; 6 | required int32 value = 3; 7 | } 8 | -------------------------------------------------------------------------------- /app/src/main/proto/CarlifeTouchFlingProto.proto: -------------------------------------------------------------------------------- 1 | package com.baidu.carlife.protobuf; 2 | message CarlifeTouchFling 3 | { 4 | required int32 x1 = 1; 5 | required int32 y1 = 2; 6 | required int32 x2 = 3; 7 | required int32 y2 = 4; 8 | required float velocityX = 5; 9 | required float velocityY = 6; 10 | } 11 | -------------------------------------------------------------------------------- /app/src/main/proto/CarlifeTouchScrollProto.proto: -------------------------------------------------------------------------------- 1 | package com.baidu.carlife.protobuf; 2 | message CarlifeTouchScroll 3 | { 4 | required int32 x1 = 1; 5 | required int32 y1 = 2; 6 | required int32 x2 = 3; 7 | required int32 y2 = 4; 8 | required float distanceX = 5; 9 | required float distanceY = 6; 10 | } 11 | -------------------------------------------------------------------------------- /app/src/main/proto/CarlifeTouchSinglePointProto.proto: -------------------------------------------------------------------------------- 1 | package com.baidu.carlife.protobuf; 2 | message CarlifeTouchSinglePoint 3 | { 4 | required int32 x = 1; 5 | required int32 y = 2; 6 | } 7 | -------------------------------------------------------------------------------- /app/src/main/proto/CarlifeVehicleInfoListProto.proto: -------------------------------------------------------------------------------- 1 | package com.baidu.carlife.protobuf; 2 | import "CarlifeVehicleInfoProto.proto"; 3 | message CarlifeVehicleInfoList 4 | { 5 | required int32 cnt = 1; 6 | repeated CarlifeVehicleInfo vehicleInfo = 2; 7 | } -------------------------------------------------------------------------------- /app/src/main/proto/CarlifeVehicleInfoProto.proto: -------------------------------------------------------------------------------- 1 | package com.baidu.carlife.protobuf; 2 | message CarlifeVehicleInfo 3 | { 4 | required int32 moduleID = 1; 5 | optional int32 flag = 2; 6 | optional int32 frequency=3; 7 | } -------------------------------------------------------------------------------- /app/src/main/proto/CarlifeVideoEncoderInfoProto.proto: -------------------------------------------------------------------------------- 1 | 2 | package com.example.car; 3 | option java_outer_classname = "CarlifeVideoEncoderInfoProto"; 4 | message CarlifeVideoEncoderInfo 5 | { 6 | required int32 width = 1; 7 | required int32 height = 2; 8 | required int32 frameRate = 3; 9 | } -------------------------------------------------------------------------------- /app/src/main/proto/CarlifeVideoFrameRateProto.proto: -------------------------------------------------------------------------------- 1 | package com.baidu.carlife.protobuf; 2 | message CarlifeVideoFrameRate 3 | { 4 | required int32 frameRate = 1; 5 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 16 | 17 | 23 | 24 | 25 | 30 | 31 | 35 | 36 | 41 | 42 | 43 | 44 | 49 | 50 | 55 | 56 | 60 | 61 | 65 | 66 | 70 | 71 | 75 | 76 |