• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2012 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.Activity;
20 import android.app.AlertDialog;
21 import android.content.BroadcastReceiver;
22 import android.content.Context;
23 import android.content.DialogInterface;
24 import android.content.Intent;
25 import android.content.IntentFilter;
26 import android.debug.IAdbManager;
27 import android.hardware.usb.UsbManager;
28 import android.os.Build;
29 import android.os.Bundle;
30 import android.os.IBinder;
31 import android.os.ServiceManager;
32 import android.os.SystemProperties;
33 import android.util.Log;
34 import android.view.LayoutInflater;
35 import android.view.View;
36 import android.view.Window;
37 import android.view.WindowManager;
38 import android.widget.CheckBox;
39 
40 import com.android.internal.app.AlertActivity;
41 import com.android.internal.app.AlertController;
42 import com.android.systemui.broadcast.BroadcastDispatcher;
43 import com.android.systemui.res.R;
44 
45 import javax.inject.Inject;
46 
47 public class UsbDebuggingActivity extends AlertActivity
48                                   implements DialogInterface.OnClickListener {
49     private static final String TAG = "UsbDebuggingActivity";
50 
51     private CheckBox mAlwaysAllow;
52     private UsbDisconnectedReceiver mDisconnectedReceiver;
53     private final BroadcastDispatcher mBroadcastDispatcher;
54     private String mKey;
55     private boolean mServiceNotified;
56 
57     @Inject
UsbDebuggingActivity(BroadcastDispatcher broadcastDispatcher)58     public UsbDebuggingActivity(BroadcastDispatcher broadcastDispatcher) {
59         super();
60         mBroadcastDispatcher = broadcastDispatcher;
61     }
62 
63     @Override
onCreate(Bundle icicle)64     public void onCreate(Bundle icicle) {
65         Window window = getWindow();
66         window.addSystemFlags(
67                 WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
68         window.setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
69 
70         super.onCreate(icicle);
71 
72         // Emulator does not support reseating the usb cable to reshow the dialog.
73         if (SystemProperties.getInt("service.adb.tcp.port", 0) == 0 && !Build.IS_EMULATOR) {
74             mDisconnectedReceiver = new UsbDisconnectedReceiver(this);
75             IntentFilter filter = new IntentFilter(UsbManager.ACTION_USB_STATE);
76             mBroadcastDispatcher.registerReceiver(mDisconnectedReceiver, filter);
77         }
78 
79         Intent intent = getIntent();
80         String fingerprints = intent.getStringExtra("fingerprints");
81         mKey = intent.getStringExtra("key");
82 
83         if (fingerprints == null || mKey == null) {
84             finish();
85             return;
86         }
87 
88         final AlertController.AlertParams ap = mAlertParams;
89         ap.mTitle = getString(R.string.usb_debugging_title);
90         ap.mMessage = getString(R.string.usb_debugging_message, fingerprints);
91         ap.mPositiveButtonText = getString(R.string.usb_debugging_allow);
92         ap.mNegativeButtonText = getString(android.R.string.cancel);
93         ap.mPositiveButtonListener = this;
94         ap.mNegativeButtonListener = this;
95 
96         // add "always allow" checkbox
97         LayoutInflater inflater = LayoutInflater.from(ap.mContext);
98         View checkbox = inflater.inflate(com.android.internal.R.layout.always_use_checkbox, null);
99         mAlwaysAllow = (CheckBox)checkbox.findViewById(com.android.internal.R.id.alwaysUse);
100         mAlwaysAllow.setText(getString(R.string.usb_debugging_always));
101         ap.mView = checkbox;
102         window.setCloseOnTouchOutside(false);
103 
104         setupAlert();
105     }
106 
107     @Override
onWindowAttributesChanged(WindowManager.LayoutParams params)108     public void onWindowAttributesChanged(WindowManager.LayoutParams params) {
109         super.onWindowAttributesChanged(params);
110     }
111 
112     private class UsbDisconnectedReceiver extends BroadcastReceiver {
113         private final Activity mActivity;
UsbDisconnectedReceiver(Activity activity)114         UsbDisconnectedReceiver(Activity activity) {
115             mActivity = activity;
116         }
117 
118         @Override
onReceive(Context content, Intent intent)119         public void onReceive(Context content, Intent intent) {
120             String action = intent.getAction();
121             if (!UsbManager.ACTION_USB_STATE.equals(action)) {
122                 return;
123             }
124             boolean connected = intent.getBooleanExtra(UsbManager.USB_CONNECTED, false);
125             if (!connected) {
126                 Log.d(TAG, "USB disconnected, notifying service");
127                 notifyService(false);
128                 mActivity.finish();
129             }
130         }
131     }
132 
133     @Override
onDestroy()134     protected void onDestroy() {
135         if (mDisconnectedReceiver != null) {
136             mBroadcastDispatcher.unregisterReceiver(mDisconnectedReceiver);
137         }
138         // Only notify the service if the activity is finishing; if onDestroy has been called due to
139         // a configuration change then allow the user to still authorize the connection the next
140         // time the activity is in the foreground.
141         if (isFinishing()) {
142             // If the ADB service has not yet been notified due to this dialog being closed in some
143             // other way then notify the service to deny the connection to ensure system_server
144             // sends a response to adbd.
145             if (!mServiceNotified) {
146                 notifyService(false);
147             }
148         }
149         super.onDestroy();
150     }
151 
152     @Override
onClick(DialogInterface dialog, int which)153     public void onClick(DialogInterface dialog, int which) {
154         boolean allow = (which == AlertDialog.BUTTON_POSITIVE);
155         boolean alwaysAllow = allow && mAlwaysAllow.isChecked();
156         notifyService(allow, alwaysAllow);
157         finish();
158     }
159 
160     /**
161      * Notifies the ADB service as to whether the current ADB request should be allowed; if the
162      * request is allowed it is only allowed for this session, and the user should be prompted again
163      * on subsequent requests from this key.
164      *
165      * @param allow whether the connection should be allowed for this session
166      */
notifyService(boolean allow)167     private void notifyService(boolean allow) {
168         notifyService(allow, false);
169     }
170 
171     /**
172      * Notifies the ADB service as to whether the current ADB request should be allowed, and if
173      * subsequent requests from this key should be allowed without user consent.
174      *
175      * @param allow whether the connection should be allowed
176      * @param alwaysAllow whether subsequent requests from this key should be allowed without user
177      *                    consent
178      */
notifyService(boolean allow, boolean alwaysAllow)179     private void notifyService(boolean allow, boolean alwaysAllow) {
180         try {
181             IBinder b = ServiceManager.getService(ADB_SERVICE);
182             IAdbManager service = IAdbManager.Stub.asInterface(b);
183             if (allow) {
184                 service.allowDebugging(alwaysAllow, mKey);
185             } else {
186                 service.denyDebugging();
187             }
188             mServiceNotified = true;
189         } catch (Exception e) {
190             Log.e(TAG, "Unable to notify Usb service", e);
191         }
192     }
193 }
194