Android T 实现简易的 USB Mode Select 需求

Android T 实现 USB Mode Select 需求

一、实现效果

二、主要实现思路

在手机连接 USB 发生/取消通知的同时,控制弹窗 Dialog 的显示/消失。

三、主要代码实现

连接 USB 发送/取消的主要实现是在 UsbDeviceManager.java 类中。类路径如下:

system/frameworks/base/services/usb/java/com/android/server/usb/UsbDeviceManager.java

具体修改代码如下:

java 复制代码
//add for bug start {
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.content.DialogInterface;
import android.view.WindowManager;
import android.view.Gravity;
// add for bug end }


/**
 * UsbDeviceManager manages USB state in device mode.
 */
public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObserver {
    
    private static final String ADB_NOTIFICATION_CHANNEL_ID_TV = "usbdevicemanager.adb.tv";

    //add for bug start {
    private static UsbHandler mHandler;

    private static AlertDialog mServiceDialog = null;
    //add for bug end }
    
    private final Object mLock = new Object();

    
        protected void updateUsbNotification(boolean force) {
            if (mNotificationManager == null || !mUseUsbNotification
                    || ("0".equals(getSystemProperty("persist.charging.notify", "")))) {
                return;
            }

            // Dont show the notification when connected to a USB peripheral
            // and the link does not support PR_SWAP and DR_SWAP
            if (mHideUsbNotification && !mSupportsAllCombinations) {
                if (mUsbNotificationId != 0) {
                    mNotificationManager.cancelAsUser(null, mUsbNotificationId,
                            UserHandle.ALL);
                    mUsbNotificationId = 0;
                    Slog.d(TAG, "Clear notification");
                }
                return;
            }

            int id = 0;
            int titleRes = 0;
            Resources r = mContext.getResources();
            CharSequence message = r.getText(
                    com.android.internal.R.string.usb_notification_message);
            if (mAudioAccessoryConnected && !mAudioAccessorySupported) {
                titleRes = com.android.internal.R.string.usb_unsupported_audio_accessory_title;
                id = SystemMessage.NOTE_USB_AUDIO_ACCESSORY_NOT_SUPPORTED;
            } 
            ....
            ....
            } else if (mHostConnected && mSinkPower && (mUsbCharging || mUsbAccessoryConnected)) {
                titleRes = com.android.internal.R.string.usb_charging_notification_title;
                id = SystemMessage.NOTE_USB_CHARGING;
            }
            if (id != mUsbNotificationId || force) {
                // clear notification if title needs changing
                if (mUsbNotificationId != 0) {
                    mNotificationManager.cancelAsUser(null, mUsbNotificationId,
                            UserHandle.ALL);
                    Slog.d(TAG, "Clear notification");
                    mUsbNotificationId = 0;
                    // add for bug start {
                    if (mServiceDialog != null){
                        mServiceDialog.dismiss();
                        mServiceDialog = null;
                    }
                    // add for bug end }
                }
                // Not relevant for automotive and watch.
                if ((mContext.getPackageManager().hasSystemFeature(
                        PackageManager.FEATURE_AUTOMOTIVE)
                        || mContext.getPackageManager().hasSystemFeature(
                        PackageManager.FEATURE_WATCH))
                        && id == SystemMessage.NOTE_USB_CHARGING) {
                    mUsbNotificationId = 0;
                    return;
                }

                if (id != 0) {
                    CharSequence title = r.getText(titleRes);
                    PendingIntent pi;
                    String channel;

                    ....
                    ....    
                    Slog.d(TAG, "push notification:" + title);
                    mUsbNotificationId = id;
                }
            }
        }

        // add for bug start {
        public void showDialog(Context context){
            final String USBModeStr[] = context.getResources().getStringArray(com.android.internal.R.array.spro_usb_mode);
            AlertDialog.Builder dialog = new AlertDialog.Builder(context);
            dialog.setTitle(context.getResources().getString(com.android.internal.R.string.usb_mode_tittle));
            dialog.setSingleChoiceItems(USBModeStr, 0 ,
                    new DialogInterface.OnClickListener(){
                        @Override
                        public void onClick(DialogInterface dialog, int which){
                            Slog.d(TAG, "----------USBModeStr------------" + USBModeStr[which]);
                            switch (which){
                                case 1:
                                    mHandler.sendMessage(MSG_SET_CURRENT_FUNCTIONS, UsbManager.FUNCTION_MTP);
                                    break;
                                case 2:
                                    mHandler.sendMessage(MSG_SET_CURRENT_FUNCTIONS, UsbManager.FUNCTION_PTP);
                                    break;
                                default:
                                    mHandler.sendMessage(MSG_SET_CURRENT_FUNCTIONS, UsbManager.FUNCTION_NONE);
                                    break;
                            }
                            dialog.dismiss();
                        }
                    }
            );
            dialog.setPositiveButton(context.getResources().getString(com.android.internal.R.string.usb_mode_cancel),
                    new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int id) {
                            dialog.cancel();
                        }
                    });
            mServiceDialog = dialog.create();
            mServiceDialog.getWindow().setType(
                    WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY);
            mServiceDialog.getWindow().setGravity(Gravity.BOTTOM);
            if (mServiceDialog != null && !mServiceDialog.isShowing()) {
                mServiceDialog.show();
            }
        }

        // add for bug end }
    
    	
            protected void updateAdbNotification(boolean force) {
            if (mNotificationManager == null) return;
            final int id = SystemMessage.NOTE_ADB_ACTIVE;

            if (isAdbEnabled() && mConnected) {
                if ("0".equals(getSystemProperty("persist.adb.notify", ""))) return;

                if (force && mAdbNotificationShown) {
                    mAdbNotificationShown = false;
                    mNotificationManager.cancelAsUser(null, id, UserHandle.ALL);
                }

                if (!mAdbNotificationShown) {
                    Notification notification = AdbNotifications.createNotification(mContext,
                            AdbTransportType.USB);
                    mAdbNotificationShown = true;
                    mNotificationManager.notifyAsUser(null, id, notification, UserHandle.ALL);

                    // add for bug start {
                    showDialog(mContext);
                    // add for bug end }
                }
            } else if (mAdbNotificationShown) {
                mAdbNotificationShown = false;
                mNotificationManager.cancelAsUser(null, id, UserHandle.ALL);
            }
        }
}
3.2、添加 string 资源
添加英文资源

frameworks\base\core\res\res\values\strings.xml

xml 复制代码
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     ... ... 
    <!--start usb mode by wj-->
    <string name="usb_mode_tittle">Use USB for</string>
    <string name="usb_mode_charging_only">Charging only</string>
    <string name="usb_mode_mtp">File Transfer(MTP)</string>
    <string name="usb_mode_ptp">Transfer Photos(PTP)</string>
    <string name="usb_mode_cancel">Cancel</string>
    <!--end usb mode by wj-->
     ... ... 
</resources>

添加中文资源

frameworks\base\core\res\res\values-zh-rCN\strings.xml

xml 复制代码
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     ... ... 
    <!--start usb mode by-->
    <string name="usb_mode_tittle">USB 用途</string>
    <string name="usb_mode_charging_only">仅限充电</string>
    <string name="usb_mode_mtp">传输文件(MTP)</string>
    <string name="usb_mode_ptp">传输照片(PTP)</string>
    <string name="usb_mode_cancel">取消</string>
    <!--end usb mode by -->
     ... ... 
</resources>
3.3、添加引用的数组资源

因为3种 USB mode,引用了数组资源,所以需要在Framework层添加数组资源。

Framework中添加数组主要修改valuesarrays.xml文件frameworks\base\core\res\res\values\arrays.xml

添加内容如下:

xml 复制代码
</resources> 
    ... ...
    <!-- add for bug start -->
    <string-array name="spro_usb_mode">
        <item>@string/usb_mode_charging_only</item>
        <item>@string/usb_mode_mtp</item>
        <item>@string/usb_mode_ptp</item>
    </string-array>
    <!-- add for bug end -->
</resources>

3.4、修改Framwork 资源,需要添加symbol,否则无法引用

Framework中添加资源后,由于无法像Eclipse或者Androd Studio那样自动生成R.java文件,需要在symbols.xml文件中手动添加自己的资源文件名,否则会导致无法根据com.android.internal.R.**引用所需的字符串资源。
symbols.xml主要在valuse文件夹下,详细路径为frameworks\base\core\res\res\values\symbols.xml

添加内容如下:

xml 复制代码
<resources>
     ... ... 
  <!--start usb mode by wj-->
  <java-symbol type="string" name="usb_mode_tittle" />
  <java-symbol type="string" name="usb_mode_charging_only" />
  <java-symbol type="string" name="usb_mode_mtp" />
  <java-symbol type="string" name="usb_mode_ptp" />
  <java-symbol type="string" name="usb_mode_cancel" />
  <java-symbol type="array" name="spro_usb_mode" />
  <!--end usb mode by wj-->
     ... ... 
</resources>
相关推荐
雨白15 小时前
Android 快捷方式实战指南:静态、动态与固定快捷方式详解
android
hqk15 小时前
鸿蒙项目实战:手把手带你实现 WanAndroid 布局与交互
android·前端·harmonyos
LING16 小时前
RN容器启动优化实践
android·react native
恋猫de小郭19 小时前
Flutter 发布官方 Skills ,Flutter 在 AI 领域再添一助力
android·前端·flutter
Kapaseker1 天前
一杯美式搞懂 Any、Unit、Nothing
android·kotlin
黄林晴1 天前
你的 Android App 还没接 AI?Gemini API 接入全攻略
android
恋猫de小郭1 天前
2026 Flutter VS React Native ,同时在 AI 时代 VS Native 开发,你没见过的版本
android·前端·flutter
冬奇Lab1 天前
PowerManagerService(上):电源状态与WakeLock管理
android·源码阅读
BoomHe2 天前
Now in Android 架构模式全面分析
android·android jetpack
二流小码农2 天前
鸿蒙开发:上传一张参考图片便可实现页面功能
android·ios·harmonyos