| /* |
| * Copyright (C) 2016 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions an |
| * limitations under the License. |
| */ |
| |
| package com.android.server.usb; |
| |
| import android.app.Notification; |
| import android.app.NotificationManager; |
| import android.app.PendingIntent; |
| import android.content.BroadcastReceiver; |
| import android.content.Context; |
| import android.content.Intent; |
| import android.content.IntentFilter; |
| import android.content.pm.PackageManager; |
| import android.content.res.Resources; |
| import android.hardware.usb.UsbConstants; |
| import android.hardware.usb.UsbDevice; |
| import android.hardware.usb.UsbInterface; |
| import android.hardware.usb.UsbManager; |
| import android.os.UserHandle; |
| |
| import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; |
| import com.android.internal.notification.SystemNotificationChannels; |
| |
| /** |
| * Manager for MTP storage notification. |
| */ |
| class MtpNotificationManager { |
| private static final String TAG = "UsbMtpNotificationManager"; |
| |
| /** |
| * Subclass for PTP. |
| */ |
| private static final int SUBCLASS_STILL_IMAGE_CAPTURE = 1; |
| |
| /** |
| * Subclass for Android style MTP. |
| */ |
| private static final int SUBCLASS_MTP = 0xff; |
| |
| /** |
| * Protocol for Picture Transfer Protocol (PIMA 15470). |
| */ |
| private static final int PROTOCOL_PTP = 1; |
| |
| /** |
| * Protocol for Android style MTP. |
| */ |
| private static final int PROTOCOL_MTP = 0; |
| |
| private static final String ACTION_OPEN_IN_APPS = "com.android.server.usb.ACTION_OPEN_IN_APPS"; |
| |
| private final Context mContext; |
| private final OnOpenInAppListener mListener; |
| |
| MtpNotificationManager(Context context, OnOpenInAppListener listener) { |
| mContext = context; |
| mListener = listener; |
| final Receiver receiver = new Receiver(); |
| context.registerReceiver(receiver, new IntentFilter(ACTION_OPEN_IN_APPS)); |
| } |
| |
| void showNotification(UsbDevice device) { |
| final Resources resources = mContext.getResources(); |
| final String title = resources.getString( |
| com.android.internal.R.string.usb_mtp_launch_notification_title, |
| device.getProductName()); |
| final String description = resources.getString( |
| com.android.internal.R.string.usb_mtp_launch_notification_description); |
| final Notification.Builder builder = |
| new Notification.Builder(mContext, SystemNotificationChannels.USB) |
| .setContentTitle(title) |
| .setContentText(description) |
| .setSmallIcon(com.android.internal.R.drawable.stat_sys_data_usb) |
| .setCategory(Notification.CATEGORY_SYSTEM); |
| |
| final Intent intent = new Intent(ACTION_OPEN_IN_APPS); |
| intent.putExtra(UsbManager.EXTRA_DEVICE, device); |
| intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND); |
| |
| final PendingIntent openIntent = PendingIntent.getBroadcastAsUser( |
| mContext, |
| device.getDeviceId(), |
| intent, |
| PendingIntent.FLAG_UPDATE_CURRENT, |
| UserHandle.SYSTEM); |
| builder.setContentIntent(openIntent); |
| |
| final Notification notification = builder.build(); |
| notification.flags |= Notification.FLAG_LOCAL_ONLY; |
| |
| mContext.getSystemService(NotificationManager.class).notify( |
| Integer.toString(device.getDeviceId()), SystemMessage.NOTE_USB_MTP_TAP, |
| notification); |
| } |
| |
| void hideNotification(int deviceId) { |
| mContext.getSystemService(NotificationManager.class).cancel( |
| Integer.toString(deviceId), SystemMessage.NOTE_USB_MTP_TAP); |
| } |
| |
| private class Receiver extends BroadcastReceiver { |
| @Override |
| public void onReceive(Context context, Intent intent) { |
| final UsbDevice device = |
| intent.getExtras().<UsbDevice>getParcelable(UsbManager.EXTRA_DEVICE); |
| if (device == null) { |
| return; |
| } |
| switch (intent.getAction()) { |
| case ACTION_OPEN_IN_APPS: |
| mListener.onOpenInApp(device); |
| break; |
| } |
| } |
| } |
| |
| static boolean shouldShowNotification(PackageManager packageManager, UsbDevice device) { |
| // We don't show MTP notification for devices that has FEATURE_AUTOMOTIVE. |
| return !packageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE) && |
| isMtpDevice(device); |
| } |
| |
| private static boolean isMtpDevice(UsbDevice device) { |
| for (int i = 0; i < device.getInterfaceCount(); i++) { |
| final UsbInterface usbInterface = device.getInterface(i); |
| if ((usbInterface.getInterfaceClass() == UsbConstants.USB_CLASS_STILL_IMAGE && |
| usbInterface.getInterfaceSubclass() == SUBCLASS_STILL_IMAGE_CAPTURE && |
| usbInterface.getInterfaceProtocol() == PROTOCOL_PTP)) { |
| return true; |
| } |
| if (usbInterface.getInterfaceClass() == UsbConstants.USB_SUBCLASS_VENDOR_SPEC && |
| usbInterface.getInterfaceSubclass() == SUBCLASS_MTP && |
| usbInterface.getInterfaceProtocol() == PROTOCOL_MTP && |
| "MTP".equals(usbInterface.getName())) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| static interface OnOpenInAppListener { |
| void onOpenInApp(UsbDevice device); |
| } |
| } |