1 /*
2  * Copyright (C) 2011 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.systemui.usb;
18 
19 import android.app.AlertDialog;
20 import android.app.PendingIntent;
21 import android.content.Context;
22 import android.content.DialogInterface;
23 import android.content.Intent;
24 import android.content.PermissionChecker;
25 import android.content.pm.ApplicationInfo;
26 import android.content.pm.PackageManager;
27 import android.hardware.usb.IUsbManager;
28 import android.hardware.usb.UsbAccessory;
29 import android.hardware.usb.UsbDevice;
30 import android.hardware.usb.UsbManager;
31 import android.os.Bundle;
32 import android.os.IBinder;
33 import android.os.RemoteException;
34 import android.os.ServiceManager;
35 import android.os.UserHandle;
36 import android.util.Log;
37 import android.view.LayoutInflater;
38 import android.view.View;
39 import android.view.WindowManager;
40 import android.widget.CheckBox;
41 import android.widget.CompoundButton;
42 import android.widget.TextView;
43 
44 import com.android.internal.app.AlertActivity;
45 import com.android.internal.app.AlertController;
46 import com.android.systemui.R;
47 
48 public class UsbPermissionActivity extends AlertActivity
49         implements DialogInterface.OnClickListener, CheckBox.OnCheckedChangeListener {
50 
51     private static final String TAG = "UsbPermissionActivity";
52 
53     private CheckBox mAlwaysUse;
54     private TextView mClearDefaultHint;
55     private UsbDevice mDevice;
56     private UsbAccessory mAccessory;
57     private PendingIntent mPendingIntent;
58     private String mPackageName;
59     private int mUid;
60     private boolean mPermissionGranted;
61     private UsbDisconnectedReceiver mDisconnectedReceiver;
62 
63     @Override
onCreate(Bundle icicle)64     public void onCreate(Bundle icicle) {
65         super.onCreate(icicle);
66 
67         getWindow().addPrivateFlags(
68                 WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
69         Intent intent = getIntent();
70         mDevice = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
71         mAccessory = (UsbAccessory)intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
72         mPendingIntent = (PendingIntent)intent.getParcelableExtra(Intent.EXTRA_INTENT);
73         mUid = intent.getIntExtra(Intent.EXTRA_UID, -1);
74         mPackageName = intent.getStringExtra(UsbManager.EXTRA_PACKAGE);
75         boolean canBeDefault = intent.getBooleanExtra(UsbManager.EXTRA_CAN_BE_DEFAULT, false);
76 
77         PackageManager packageManager = getPackageManager();
78         ApplicationInfo aInfo;
79         try {
80             aInfo = packageManager.getApplicationInfo(mPackageName, 0);
81         } catch (PackageManager.NameNotFoundException e) {
82             Log.e(TAG, "unable to look up package name", e);
83             finish();
84             return;
85         }
86         String appName = aInfo.loadLabel(packageManager).toString();
87 
88         final AlertController.AlertParams ap = mAlertParams;
89         ap.mTitle = appName;
90         boolean useRecordWarning = false;
91         if (mDevice == null) {
92             // Accessory Case
93 
94             ap.mMessage = getString(R.string.usb_accessory_permission_prompt, appName,
95                     mAccessory.getDescription());
96             mDisconnectedReceiver = new UsbDisconnectedReceiver(this, mAccessory);
97         } else {
98             boolean hasRecordPermission =
99                     PermissionChecker.checkPermissionForPreflight(
100                             this, android.Manifest.permission.RECORD_AUDIO, -1, aInfo.uid,
101                             mPackageName)
102                             == android.content.pm.PackageManager.PERMISSION_GRANTED;
103             boolean isAudioCaptureDevice = mDevice.getHasAudioCapture();
104             useRecordWarning = isAudioCaptureDevice && !hasRecordPermission;
105 
106             int strID = useRecordWarning
107                     ? R.string.usb_device_permission_prompt_warn
108                     : R.string.usb_device_permission_prompt;
109             ap.mMessage = getString(strID, appName, mDevice.getProductName());
110             mDisconnectedReceiver = new UsbDisconnectedReceiver(this, mDevice);
111 
112         }
113 
114         ap.mPositiveButtonText = getString(android.R.string.ok);
115         ap.mNegativeButtonText = getString(android.R.string.cancel);
116         ap.mPositiveButtonListener = this;
117         ap.mNegativeButtonListener = this;
118 
119         // Don't show the "always use" checkbox if the USB/Record warning is in effect
120         if (!useRecordWarning && canBeDefault && (mDevice != null || mAccessory != null)) {
121             // add "open when" checkbox
122             LayoutInflater inflater = (LayoutInflater) getSystemService(
123                     Context.LAYOUT_INFLATER_SERVICE);
124             ap.mView = inflater.inflate(com.android.internal.R.layout.always_use_checkbox, null);
125             mAlwaysUse = (CheckBox) ap.mView.findViewById(com.android.internal.R.id.alwaysUse);
126             if (mDevice == null) {
127                 mAlwaysUse.setText(getString(R.string.always_use_accessory, appName,
128                         mAccessory.getDescription()));
129             } else {
130                 mAlwaysUse.setText(getString(R.string.always_use_device, appName,
131                         mDevice.getProductName()));
132             }
133             mAlwaysUse.setOnCheckedChangeListener(this);
134 
135             mClearDefaultHint = (TextView)ap.mView.findViewById(
136                     com.android.internal.R.id.clearDefaultHint);
137             mClearDefaultHint.setVisibility(View.GONE);
138         }
139 
140         setupAlert();
141     }
142 
143     @Override
onDestroy()144     public void onDestroy() {
145         IBinder b = ServiceManager.getService(USB_SERVICE);
146         IUsbManager service = IUsbManager.Stub.asInterface(b);
147 
148         // send response via pending intent
149         Intent intent = new Intent();
150         try {
151             if (mDevice != null) {
152                 intent.putExtra(UsbManager.EXTRA_DEVICE, mDevice);
153                 if (mPermissionGranted) {
154                     service.grantDevicePermission(mDevice, mUid);
155                     if (mAlwaysUse != null && mAlwaysUse.isChecked()) {
156                         final int userId = UserHandle.getUserId(mUid);
157                         service.setDevicePackage(mDevice, mPackageName, userId);
158                     }
159                 }
160             }
161             if (mAccessory != null) {
162                 intent.putExtra(UsbManager.EXTRA_ACCESSORY, mAccessory);
163                 if (mPermissionGranted) {
164                     service.grantAccessoryPermission(mAccessory, mUid);
165                     if (mAlwaysUse != null && mAlwaysUse.isChecked()) {
166                         final int userId = UserHandle.getUserId(mUid);
167                         service.setAccessoryPackage(mAccessory, mPackageName, userId);
168                     }
169                 }
170             }
171             intent.putExtra(UsbManager.EXTRA_PERMISSION_GRANTED, mPermissionGranted);
172             mPendingIntent.send(this, 0, intent);
173         } catch (PendingIntent.CanceledException e) {
174             Log.w(TAG, "PendingIntent was cancelled");
175         } catch (RemoteException e) {
176             Log.e(TAG, "IUsbService connection failed", e);
177         }
178 
179         if (mDisconnectedReceiver != null) {
180             unregisterReceiver(mDisconnectedReceiver);
181         }
182         super.onDestroy();
183     }
184 
onClick(DialogInterface dialog, int which)185     public void onClick(DialogInterface dialog, int which) {
186         if (which == AlertDialog.BUTTON_POSITIVE) {
187             mPermissionGranted = true;
188         }
189         finish();
190     }
191 
onCheckedChanged(CompoundButton buttonView, boolean isChecked)192     public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
193         if (mClearDefaultHint == null) return;
194 
195         if(isChecked) {
196             mClearDefaultHint.setVisibility(View.VISIBLE);
197         } else {
198             mClearDefaultHint.setVisibility(View.GONE);
199         }
200     }
201 }
202