OSDN Git Service

Fix issue #9074296: Device Admins can activate in a way...
[android-x86/packages-apps-Settings.git] / src / com / android / settings / DeviceAdminAdd.java
1 /*
2  * Copyright (C) 2010 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.settings;
18
19 import org.xmlpull.v1.XmlPullParserException;
20
21 import android.app.Activity;
22 import android.app.ActivityManagerNative;
23 import android.app.AlertDialog;
24 import android.app.Dialog;
25 import android.app.admin.DeviceAdminInfo;
26 import android.app.admin.DeviceAdminReceiver;
27 import android.app.admin.DevicePolicyManager;
28 import android.content.ComponentName;
29 import android.content.Context;
30 import android.content.DialogInterface;
31 import android.content.Intent;
32 import android.content.pm.ActivityInfo;
33 import android.content.pm.PackageManager;
34 import android.content.pm.ResolveInfo;
35 import android.content.res.Resources;
36 import android.os.Bundle;
37 import android.os.Handler;
38 import android.os.RemoteCallback;
39 import android.os.RemoteException;
40 import android.text.TextUtils.TruncateAt;
41 import android.util.Log;
42 import android.view.Display;
43 import android.view.View;
44 import android.view.ViewGroup;
45 import android.view.WindowManager;
46 import android.widget.AppSecurityPermissions;
47 import android.widget.Button;
48 import android.widget.ImageView;
49 import android.widget.TextView;
50
51 import java.io.IOException;
52 import java.util.ArrayList;
53 import java.util.HashSet;
54 import java.util.List;
55
56 public class DeviceAdminAdd extends Activity {
57     static final String TAG = "DeviceAdminAdd";
58     
59     static final int DIALOG_WARNING = 1;
60
61     private static final int MAX_ADD_MSG_LINES_PORTRAIT = 5;
62     private static final int MAX_ADD_MSG_LINES_LANDSCAPE = 2;
63     private static final int MAX_ADD_MSG_LINES = 15;
64     
65     Handler mHandler;
66     
67     DevicePolicyManager mDPM;
68     DeviceAdminInfo mDeviceAdmin;
69     CharSequence mAddMsgText;
70     
71     ImageView mAdminIcon;
72     TextView mAdminName;
73     TextView mAdminDescription;
74     TextView mAddMsg;
75     ImageView mAddMsgExpander;
76     boolean mAddMsgEllipsized = true;
77     TextView mAdminWarning;
78     ViewGroup mAdminPolicies;
79     Button mActionButton;
80     Button mCancelButton;
81     
82     final ArrayList<View> mAddingPolicies = new ArrayList<View>();
83     final ArrayList<View> mActivePolicies = new ArrayList<View>();
84     
85     boolean mAdding;
86     boolean mRefreshing;
87     
88     @Override
89     protected void onCreate(Bundle icicle) {
90         super.onCreate(icicle);
91
92         mHandler = new Handler(getMainLooper());
93         
94         mDPM = (DevicePolicyManager)getSystemService(Context.DEVICE_POLICY_SERVICE);
95
96         if ((getIntent().getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
97             Log.w(TAG, "Cannot start ADD_DEVICE_ADMIN as a new task");
98             finish();
99             return;
100         }
101         
102         ComponentName cn = (ComponentName)getIntent().getParcelableExtra(
103                 DevicePolicyManager.EXTRA_DEVICE_ADMIN);
104         if (cn == null) {
105             Log.w(TAG, "No component specified in " + getIntent().getAction());
106             finish();
107             return;
108         }
109
110         ActivityInfo ai;
111         try {
112             ai = getPackageManager().getReceiverInfo(cn, PackageManager.GET_META_DATA);
113         } catch (PackageManager.NameNotFoundException e) {
114             Log.w(TAG, "Unable to retrieve device policy " + cn, e);
115             finish();
116             return;
117         }
118
119         // Make sure the given component name is actually a valid device admin.
120         List<ResolveInfo> avail = getPackageManager().queryBroadcastReceivers(
121                 new Intent(DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED),
122                 PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS);
123         int count = avail == null ? 0 : avail.size();
124         boolean found = false;
125         for (int i=0; i<count; i++) {
126             ResolveInfo ri = avail.get(i);
127             if (ai.packageName.equals(ri.activityInfo.packageName)
128                     && ai.name.equals(ri.activityInfo.name)) {
129                 try {
130                     // We didn't retrieve the meta data for all possible matches, so
131                     // need to use the activity info of this specific one that was retrieved.
132                     ri.activityInfo = ai;
133                     DeviceAdminInfo dpi = new DeviceAdminInfo(this, ri);
134                     found = true;
135                 } catch (XmlPullParserException e) {
136                     Log.w(TAG, "Bad " + ri.activityInfo, e);
137                 } catch (IOException e) {
138                     Log.w(TAG, "Bad " + ri.activityInfo, e);
139                 }
140                 break;
141             }
142         }
143         if (!found) {
144             Log.w(TAG, "Request to add invalid device admin: " + cn);
145             finish();
146             return;
147         }
148
149         ResolveInfo ri = new ResolveInfo();
150         ri.activityInfo = ai;
151         try {
152             mDeviceAdmin = new DeviceAdminInfo(this, ri);
153         } catch (XmlPullParserException e) {
154             Log.w(TAG, "Unable to retrieve device policy " + cn, e);
155             finish();
156             return;
157         } catch (IOException e) {
158             Log.w(TAG, "Unable to retrieve device policy " + cn, e);
159             finish();
160             return;
161         }
162         
163         // This admin already exists, an we have two options at this point.  If new policy
164         // bits are set, show the user the new list.  If nothing has changed, simply return
165         // "OK" immediately.
166         if (DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN.equals(getIntent().getAction())) {
167             mRefreshing = false;
168             if (mDPM.isAdminActive(cn)) {
169                 ArrayList<DeviceAdminInfo.PolicyInfo> newPolicies = mDeviceAdmin.getUsedPolicies();
170                 for (int i = 0; i < newPolicies.size(); i++) {
171                     DeviceAdminInfo.PolicyInfo pi = newPolicies.get(i);
172                     if (!mDPM.hasGrantedPolicy(cn, pi.ident)) {
173                         mRefreshing = true;
174                         break;
175                     }
176                 }
177                 if (!mRefreshing) {
178                     // Nothing changed (or policies were removed) - return immediately
179                     setResult(Activity.RESULT_OK);
180                     finish();
181                     return;
182                 }
183             }
184         }
185         mAddMsgText = getIntent().getCharSequenceExtra(DevicePolicyManager.EXTRA_ADD_EXPLANATION);
186
187         setContentView(R.layout.device_admin_add);
188         
189         mAdminIcon = (ImageView)findViewById(R.id.admin_icon);
190         mAdminName = (TextView)findViewById(R.id.admin_name);
191         mAdminDescription = (TextView)findViewById(R.id.admin_description);
192
193         mAddMsg = (TextView)findViewById(R.id.add_msg);
194         mAddMsgExpander = (ImageView) findViewById(R.id.add_msg_expander);
195         mAddMsg.setOnClickListener(new View.OnClickListener() {
196             public void onClick(View v) {
197                 toggleMessageEllipsis(v);
198             }
199         });
200
201         // toggleMessageEllipsis also handles initial layout:
202         toggleMessageEllipsis(mAddMsg);
203
204         mAdminWarning = (TextView) findViewById(R.id.admin_warning);
205         mAdminPolicies = (ViewGroup) findViewById(R.id.admin_policies);
206         mCancelButton = (Button) findViewById(R.id.cancel_button);
207         mCancelButton.setOnClickListener(new View.OnClickListener() {
208             public void onClick(View v) {
209                 finish();
210             }
211         });
212         mActionButton = (Button) findViewById(R.id.action_button);
213         mActionButton.setOnClickListener(new View.OnClickListener() {
214             public void onClick(View v) {
215                 if (mAdding) {
216                     try {
217                         mDPM.setActiveAdmin(mDeviceAdmin.getComponent(), mRefreshing);
218                         setResult(Activity.RESULT_OK);
219                     } catch (RuntimeException e) {
220                         // Something bad happened...  could be that it was
221                         // already set, though.
222                         Log.w(TAG, "Exception trying to activate admin "
223                                 + mDeviceAdmin.getComponent(), e);
224                         if (mDPM.isAdminActive(mDeviceAdmin.getComponent())) {
225                             setResult(Activity.RESULT_OK);
226                         }
227                     }
228                     finish();
229                 } else {
230                     try {
231                         // Don't allow the admin to put a dialog up in front
232                         // of us while we interact with the user.
233                         ActivityManagerNative.getDefault().stopAppSwitches();
234                     } catch (RemoteException e) {
235                     }
236                     mDPM.getRemoveWarning(mDeviceAdmin.getComponent(),
237                             new RemoteCallback(mHandler) {
238                         @Override
239                         protected void onResult(Bundle bundle) {
240                             CharSequence msg = bundle != null
241                                     ? bundle.getCharSequence(
242                                             DeviceAdminReceiver.EXTRA_DISABLE_WARNING)
243                                     : null;
244                             if (msg == null) {
245                                 try {
246                                     ActivityManagerNative.getDefault().resumeAppSwitches();
247                                 } catch (RemoteException e) {
248                                 }
249                                 mDPM.removeActiveAdmin(mDeviceAdmin.getComponent());
250                                 finish();
251                             } else {
252                                 Bundle args = new Bundle();
253                                 args.putCharSequence(
254                                         DeviceAdminReceiver.EXTRA_DISABLE_WARNING, msg);
255                                 showDialog(DIALOG_WARNING, args);
256                             }
257                         }
258                     });
259                 }
260             }
261         });
262     }
263     
264     @Override
265     protected void onResume() {
266         super.onResume();
267         updateInterface();
268     }
269     
270     @Override
271     protected Dialog onCreateDialog(int id, Bundle args) {
272         switch (id) {
273             case DIALOG_WARNING: {
274                 CharSequence msg = args.getCharSequence(DeviceAdminReceiver.EXTRA_DISABLE_WARNING);
275                 AlertDialog.Builder builder = new AlertDialog.Builder(
276                         DeviceAdminAdd.this);
277                 builder.setMessage(msg);
278                 builder.setPositiveButton(R.string.dlg_ok,
279                         new DialogInterface.OnClickListener() {
280                     public void onClick(DialogInterface dialog, int which) {
281                         mDPM.removeActiveAdmin(mDeviceAdmin.getComponent());
282                         finish();
283                     }
284                 });
285                 builder.setNegativeButton(R.string.dlg_cancel, null);
286                 return builder.create();
287             }
288             default:
289                 return super.onCreateDialog(id, args);
290                     
291         }
292     }
293     
294     static void setViewVisibility(ArrayList<View> views, int visibility) {
295         final int N = views.size();
296         for (int i=0; i<N; i++) {
297             views.get(i).setVisibility(visibility);
298         }
299     }
300     
301     void updateInterface() {
302         mAdminIcon.setImageDrawable(mDeviceAdmin.loadIcon(getPackageManager()));
303         mAdminName.setText(mDeviceAdmin.loadLabel(getPackageManager()));
304         try {
305             mAdminDescription.setText(
306                     mDeviceAdmin.loadDescription(getPackageManager()));
307             mAdminDescription.setVisibility(View.VISIBLE);
308         } catch (Resources.NotFoundException e) {
309             mAdminDescription.setVisibility(View.GONE);
310         }
311         if (mAddMsgText != null) {
312             mAddMsg.setText(mAddMsgText);
313             mAddMsg.setVisibility(View.VISIBLE);
314         } else {
315             mAddMsg.setVisibility(View.GONE);
316             mAddMsgExpander.setVisibility(View.GONE);
317         }
318         if (!mRefreshing && mDPM.isAdminActive(mDeviceAdmin.getComponent())) {
319             if (mActivePolicies.size() == 0) {
320                 ArrayList<DeviceAdminInfo.PolicyInfo> policies = mDeviceAdmin.getUsedPolicies();
321                 for (int i=0; i<policies.size(); i++) {
322                     DeviceAdminInfo.PolicyInfo pi = policies.get(i);
323                     View view = AppSecurityPermissions.getPermissionItemView(
324                             this, getText(pi.label), "", true);
325                     mActivePolicies.add(view);
326                     mAdminPolicies.addView(view);
327                 }
328             }
329             setViewVisibility(mActivePolicies, View.VISIBLE);
330             setViewVisibility(mAddingPolicies, View.GONE);
331             mAdminWarning.setText(getString(R.string.device_admin_status,
332                     mDeviceAdmin.getActivityInfo().applicationInfo.loadLabel(getPackageManager())));
333             setTitle(getText(R.string.active_device_admin_msg));
334             mActionButton.setText(getText(R.string.remove_device_admin));
335             mAdding = false;
336         } else {
337             if (mAddingPolicies.size() == 0) {
338                 ArrayList<DeviceAdminInfo.PolicyInfo> policies = mDeviceAdmin.getUsedPolicies();
339                 for (int i=0; i<policies.size(); i++) {
340                     DeviceAdminInfo.PolicyInfo pi = policies.get(i);
341                     View view = AppSecurityPermissions.getPermissionItemView(
342                             this, getText(pi.label), getText(pi.description), true);
343                     mAddingPolicies.add(view);
344                     mAdminPolicies.addView(view);
345                 }
346             }
347             setViewVisibility(mAddingPolicies, View.VISIBLE);
348             setViewVisibility(mActivePolicies, View.GONE);
349             mAdminWarning.setText(getString(R.string.device_admin_warning,
350                     mDeviceAdmin.getActivityInfo().applicationInfo.loadLabel(getPackageManager())));
351             setTitle(getText(R.string.add_device_admin_msg));
352             mActionButton.setText(getText(R.string.add_device_admin));
353             mAdding = true;
354         }
355     }
356
357
358     void toggleMessageEllipsis(View v) {
359         TextView tv = (TextView) v;
360
361         mAddMsgEllipsized = ! mAddMsgEllipsized;
362         tv.setEllipsize(mAddMsgEllipsized ? TruncateAt.END : null);
363         tv.setMaxLines(mAddMsgEllipsized ? getEllipsizedLines() : MAX_ADD_MSG_LINES);
364
365         mAddMsgExpander.setImageResource(mAddMsgEllipsized ?
366             com.android.internal.R.drawable.expander_ic_minimized :
367             com.android.internal.R.drawable.expander_ic_maximized);
368     }
369
370     int getEllipsizedLines() {
371         Display d = ((WindowManager) getSystemService(Context.WINDOW_SERVICE))
372                     .getDefaultDisplay();
373
374         return d.getHeight() > d.getWidth() ?
375             MAX_ADD_MSG_LINES_PORTRAIT : MAX_ADD_MSG_LINES_LANDSCAPE;
376     }
377
378 }