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 android.app.Activity;
20 import android.app.ActivityManagerNative;
21 import android.app.AlertDialog;
22 import android.app.AppOpsManager;
23 import android.app.Dialog;
24 import android.app.admin.DeviceAdminInfo;
25 import android.app.admin.DeviceAdminReceiver;
26 import android.app.admin.DevicePolicyManager;
27 import android.content.ComponentName;
28 import android.content.Context;
29 import android.content.DialogInterface;
30 import android.content.Intent;
31 import android.content.pm.ActivityInfo;
32 import android.content.pm.ApplicationInfo;
33 import android.content.pm.PackageInfo;
34 import android.content.pm.PackageManager;
35 import android.content.pm.PackageManager.NameNotFoundException;
36 import android.content.pm.ResolveInfo;
37 import android.content.pm.UserInfo;
38 import android.content.res.Resources;
39 import android.net.Uri;
40 import android.os.Binder;
41 import android.os.Bundle;
42 import android.os.Handler;
43 import android.os.RemoteCallback;
44 import android.os.RemoteException;
45 import android.os.UserHandle;
46 import android.os.UserManager;
47 import android.text.TextUtils;
48 import android.text.TextUtils.TruncateAt;
49 import android.util.EventLog;
50 import android.util.Log;
51 import android.view.Display;
52 import android.view.View;
53 import android.view.ViewGroup;
54 import android.view.ViewTreeObserver;
55 import android.view.WindowManager;
56 import android.widget.AppSecurityPermissions;
57 import android.widget.Button;
58 import android.widget.ImageView;
59 import android.widget.TextView;
60 
61 import com.android.settings.users.UserDialogs;
62 
63 import org.xmlpull.v1.XmlPullParserException;
64 
65 import java.io.IOException;
66 import java.util.ArrayList;
67 import java.util.List;
68 
69 public class DeviceAdminAdd extends Activity {
70     static final String TAG = "DeviceAdminAdd";
71 
72     static final int DIALOG_WARNING = 1;
73 
74     private static final int MAX_ADD_MSG_LINES_PORTRAIT = 5;
75     private static final int MAX_ADD_MSG_LINES_LANDSCAPE = 2;
76     private static final int MAX_ADD_MSG_LINES = 15;
77 
78     /**
79      * Optional key to map to the package name of the Device Admin.
80      * Currently only used when uninstalling an active device admin.
81      */
82     public static final String EXTRA_DEVICE_ADMIN_PACKAGE_NAME =
83             "android.app.extra.DEVICE_ADMIN_PACKAGE_NAME";
84 
85     public static final String EXTRA_CALLED_FROM_SUPPORT_DIALOG =
86             "android.app.extra.CALLED_FROM_SUPPORT_DIALOG";
87 
88     Handler mHandler;
89 
90     DevicePolicyManager mDPM;
91     AppOpsManager mAppOps;
92     DeviceAdminInfo mDeviceAdmin;
93     CharSequence mAddMsgText;
94     String mProfileOwnerName;
95 
96     ImageView mAdminIcon;
97     TextView mAdminName;
98     TextView mAdminDescription;
99     TextView mAddMsg;
100     TextView mProfileOwnerWarning;
101     ImageView mAddMsgExpander;
102     boolean mAddMsgEllipsized = true;
103     TextView mAdminWarning;
104     TextView mSupportMessage;
105     ViewGroup mAdminPolicies;
106     Button mActionButton;
107     Button mUninstallButton;
108     Button mCancelButton;
109 
110     boolean mUninstalling = false;
111     boolean mAdding;
112     boolean mRefreshing;
113     boolean mWaitingForRemoveMsg;
114     boolean mAddingProfileOwner;
115     boolean mAdminPoliciesInitialized;
116     int mCurSysAppOpMode;
117     int mCurToastAppOpMode;
118 
119     boolean mIsCalledFromSupportDialog = false;
120 
121     @Override
onCreate(Bundle icicle)122     protected void onCreate(Bundle icicle) {
123         super.onCreate(icicle);
124 
125         mHandler = new Handler(getMainLooper());
126 
127         mDPM = (DevicePolicyManager)getSystemService(Context.DEVICE_POLICY_SERVICE);
128         mAppOps = (AppOpsManager)getSystemService(Context.APP_OPS_SERVICE);
129         PackageManager packageManager = getPackageManager();
130 
131         if ((getIntent().getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
132             Log.w(TAG, "Cannot start ADD_DEVICE_ADMIN as a new task");
133             finish();
134             return;
135         }
136 
137         mIsCalledFromSupportDialog = getIntent().getBooleanExtra(
138                 EXTRA_CALLED_FROM_SUPPORT_DIALOG, false);
139 
140         String action = getIntent().getAction();
141         ComponentName who = (ComponentName)getIntent().getParcelableExtra(
142                 DevicePolicyManager.EXTRA_DEVICE_ADMIN);
143         if (who == null) {
144             String packageName = getIntent().getStringExtra(EXTRA_DEVICE_ADMIN_PACKAGE_NAME);
145             for (ComponentName component : mDPM.getActiveAdmins()) {
146                 if (component.getPackageName().equals(packageName)) {
147                     who = component;
148                     mUninstalling = true;
149                     break;
150                 }
151             }
152             if (who == null) {
153                 Log.w(TAG, "No component specified in " + action);
154                 finish();
155                 return;
156             }
157         }
158 
159         if (action != null && action.equals(DevicePolicyManager.ACTION_SET_PROFILE_OWNER)) {
160             setResult(RESULT_CANCELED);
161             setFinishOnTouchOutside(true);
162             mAddingProfileOwner = true;
163             mProfileOwnerName =
164                     getIntent().getStringExtra(DevicePolicyManager.EXTRA_PROFILE_OWNER_NAME);
165             String callingPackage = getCallingPackage();
166             if (callingPackage == null || !callingPackage.equals(who.getPackageName())) {
167                 Log.e(TAG, "Unknown or incorrect caller");
168                 finish();
169                 return;
170             }
171             try {
172                 PackageInfo packageInfo = packageManager.getPackageInfo(callingPackage, 0);
173                 if ((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
174                     Log.e(TAG, "Cannot set a non-system app as a profile owner");
175                     finish();
176                     return;
177                 }
178             } catch (NameNotFoundException nnfe) {
179                 Log.e(TAG, "Cannot find the package " + callingPackage);
180                 finish();
181                 return;
182             }
183         }
184 
185         ActivityInfo ai;
186         try {
187             ai = packageManager.getReceiverInfo(who, PackageManager.GET_META_DATA);
188         } catch (PackageManager.NameNotFoundException e) {
189             Log.w(TAG, "Unable to retrieve device policy " + who, e);
190             finish();
191             return;
192         }
193 
194         // When activating, make sure the given component name is actually a valid device admin.
195         // No need to check this when deactivating, because it is safe to deactivate an active
196         // invalid device admin.
197         if (!mDPM.isAdminActive(who)) {
198             List<ResolveInfo> avail = packageManager.queryBroadcastReceivers(
199                     new Intent(DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED),
200                     PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS);
201             int count = avail == null ? 0 : avail.size();
202             boolean found = false;
203             for (int i=0; i<count; i++) {
204                 ResolveInfo ri = avail.get(i);
205                 if (ai.packageName.equals(ri.activityInfo.packageName)
206                         && ai.name.equals(ri.activityInfo.name)) {
207                     try {
208                         // We didn't retrieve the meta data for all possible matches, so
209                         // need to use the activity info of this specific one that was retrieved.
210                         ri.activityInfo = ai;
211                         DeviceAdminInfo dpi = new DeviceAdminInfo(this, ri);
212                         found = true;
213                     } catch (XmlPullParserException e) {
214                         Log.w(TAG, "Bad " + ri.activityInfo, e);
215                     } catch (IOException e) {
216                         Log.w(TAG, "Bad " + ri.activityInfo, e);
217                     }
218                     break;
219                 }
220             }
221             if (!found) {
222                 Log.w(TAG, "Request to add invalid device admin: " + who);
223                 finish();
224                 return;
225             }
226         }
227 
228         ResolveInfo ri = new ResolveInfo();
229         ri.activityInfo = ai;
230         try {
231             mDeviceAdmin = new DeviceAdminInfo(this, ri);
232         } catch (XmlPullParserException e) {
233             Log.w(TAG, "Unable to retrieve device policy " + who, e);
234             finish();
235             return;
236         } catch (IOException e) {
237             Log.w(TAG, "Unable to retrieve device policy " + who, e);
238             finish();
239             return;
240         }
241 
242         // This admin already exists, an we have two options at this point.  If new policy
243         // bits are set, show the user the new list.  If nothing has changed, simply return
244         // "OK" immediately.
245         if (DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN.equals(getIntent().getAction())) {
246             mRefreshing = false;
247             if (mDPM.isAdminActive(who)) {
248                 if (mDPM.isRemovingAdmin(who, android.os.Process.myUserHandle().getIdentifier())) {
249                     Log.w(TAG, "Requested admin is already being removed: " + who);
250                     finish();
251                     return;
252                 }
253 
254                 ArrayList<DeviceAdminInfo.PolicyInfo> newPolicies = mDeviceAdmin.getUsedPolicies();
255                 for (int i = 0; i < newPolicies.size(); i++) {
256                     DeviceAdminInfo.PolicyInfo pi = newPolicies.get(i);
257                     if (!mDPM.hasGrantedPolicy(who, pi.ident)) {
258                         mRefreshing = true;
259                         break;
260                     }
261                 }
262                 if (!mRefreshing) {
263                     // Nothing changed (or policies were removed) - return immediately
264                     setResult(Activity.RESULT_OK);
265                     finish();
266                     return;
267                 }
268             }
269         }
270 
271         // If we're trying to add a profile owner and user setup hasn't completed yet, no
272         // need to prompt for permission. Just add and finish.
273         if (mAddingProfileOwner && !mDPM.hasUserSetupCompleted()) {
274             addAndFinish();
275             return;
276         }
277 
278         mAddMsgText = getIntent().getCharSequenceExtra(DevicePolicyManager.EXTRA_ADD_EXPLANATION);
279 
280         setContentView(R.layout.device_admin_add);
281 
282         mAdminIcon = (ImageView)findViewById(R.id.admin_icon);
283         mAdminName = (TextView)findViewById(R.id.admin_name);
284         mAdminDescription = (TextView)findViewById(R.id.admin_description);
285         mProfileOwnerWarning = (TextView) findViewById(R.id.profile_owner_warning);
286 
287         mAddMsg = (TextView)findViewById(R.id.add_msg);
288         mAddMsgExpander = (ImageView) findViewById(R.id.add_msg_expander);
289         final View.OnClickListener onClickListener = new View.OnClickListener() {
290             @Override
291             public void onClick(View v) {
292                 toggleMessageEllipsis(mAddMsg);
293             }
294         };
295         mAddMsgExpander.setOnClickListener(onClickListener);
296         mAddMsg.setOnClickListener(onClickListener);
297 
298         // Determine whether the message can be collapsed - getLineCount() gives the correct
299         // number of lines only after a layout pass.
300         mAddMsg.getViewTreeObserver().addOnGlobalLayoutListener(
301                 new ViewTreeObserver.OnGlobalLayoutListener() {
302                     @Override
303                     public void onGlobalLayout() {
304                         final int maxLines = getEllipsizedLines();
305                         // hide the icon if number of visible lines does not exceed maxLines
306                         boolean hideMsgExpander = mAddMsg.getLineCount() <= maxLines;
307                         mAddMsgExpander.setVisibility(hideMsgExpander ? View.GONE : View.VISIBLE);
308                         if (hideMsgExpander) {
309                             mAddMsg.setOnClickListener(null);
310                             ((View)mAddMsgExpander.getParent()).invalidate();
311                         }
312                         mAddMsg.getViewTreeObserver().removeOnGlobalLayoutListener(this);
313                     }
314                 });
315 
316         // toggleMessageEllipsis also handles initial layout:
317         toggleMessageEllipsis(mAddMsg);
318 
319         mAdminWarning = (TextView) findViewById(R.id.admin_warning);
320         mAdminPolicies = (ViewGroup) findViewById(R.id.admin_policies);
321         mSupportMessage = (TextView) findViewById(R.id.admin_support_message);
322 
323         mCancelButton = (Button) findViewById(R.id.cancel_button);
324         mCancelButton.setFilterTouchesWhenObscured(true);
325         mCancelButton.setOnClickListener(new View.OnClickListener() {
326             public void onClick(View v) {
327                 EventLog.writeEvent(EventLogTags.EXP_DET_DEVICE_ADMIN_DECLINED_BY_USER,
328                     mDeviceAdmin.getActivityInfo().applicationInfo.uid);
329                 finish();
330             }
331         });
332 
333         mUninstallButton = (Button) findViewById(R.id.uninstall_button);
334         mUninstallButton.setFilterTouchesWhenObscured(true);
335         mUninstallButton.setOnClickListener(new View.OnClickListener() {
336             public void onClick(View v) {
337                 EventLog.writeEvent(EventLogTags.EXP_DET_DEVICE_ADMIN_UNINSTALLED_BY_USER,
338                         mDeviceAdmin.getActivityInfo().applicationInfo.uid);
339                 mDPM.uninstallPackageWithActiveAdmins(mDeviceAdmin.getPackageName());
340                 finish();
341             }
342         });
343 
344         mActionButton = (Button) findViewById(R.id.action_button);
345         mActionButton.setFilterTouchesWhenObscured(true);
346         mActionButton.setOnClickListener(new View.OnClickListener() {
347             public void onClick(View v) {
348                 if (mAdding) {
349                     addAndFinish();
350                 } else if (isManagedProfile(mDeviceAdmin)
351                         && mDeviceAdmin.getComponent().equals(mDPM.getProfileOwner())) {
352                     final int userId = UserHandle.myUserId();
353                     UserDialogs.createRemoveDialog(DeviceAdminAdd.this, userId,
354                             new DialogInterface.OnClickListener() {
355                                 @Override
356                                 public void onClick(DialogInterface dialog, int which) {
357                                     UserManager um = UserManager.get(DeviceAdminAdd.this);
358                                     um.removeUser(userId);
359                                     finish();
360                                 }
361                             }
362                             ).show();
363                 } else if (mUninstalling) {
364                     mDPM.uninstallPackageWithActiveAdmins(mDeviceAdmin.getPackageName());
365                     finish();
366                 } else if (!mWaitingForRemoveMsg) {
367                     try {
368                         // Don't allow the admin to put a dialog up in front
369                         // of us while we interact with the user.
370                         ActivityManagerNative.getDefault().stopAppSwitches();
371                     } catch (RemoteException e) {
372                     }
373                     mWaitingForRemoveMsg = true;
374                     mDPM.getRemoveWarning(mDeviceAdmin.getComponent(),
375                             new RemoteCallback(new RemoteCallback.OnResultListener() {
376                                 @Override
377                                 public void onResult(Bundle result) {
378                                     CharSequence msg = result != null
379                                             ? result.getCharSequence(
380                                             DeviceAdminReceiver.EXTRA_DISABLE_WARNING)
381                                             : null;
382                                     continueRemoveAction(msg);
383                                 }
384                             }, mHandler));
385                     // Don't want to wait too long.
386                     getWindow().getDecorView().getHandler().postDelayed(new Runnable() {
387                         @Override public void run() {
388                             continueRemoveAction(null);
389                         }
390                     }, 2*1000);
391                 }
392             }
393         });
394     }
395 
addAndFinish()396     void addAndFinish() {
397         try {
398             mDPM.setActiveAdmin(mDeviceAdmin.getComponent(), mRefreshing);
399             EventLog.writeEvent(EventLogTags.EXP_DET_DEVICE_ADMIN_ACTIVATED_BY_USER,
400                 mDeviceAdmin.getActivityInfo().applicationInfo.uid);
401             setResult(Activity.RESULT_OK);
402         } catch (RuntimeException e) {
403             // Something bad happened...  could be that it was
404             // already set, though.
405             Log.w(TAG, "Exception trying to activate admin "
406                     + mDeviceAdmin.getComponent(), e);
407             if (mDPM.isAdminActive(mDeviceAdmin.getComponent())) {
408                 setResult(Activity.RESULT_OK);
409             }
410         }
411         if (mAddingProfileOwner) {
412             try {
413                 mDPM.setProfileOwner(mDeviceAdmin.getComponent(),
414                         mProfileOwnerName, UserHandle.myUserId());
415             } catch (RuntimeException re) {
416                 setResult(Activity.RESULT_CANCELED);
417             }
418         }
419         finish();
420     }
421 
continueRemoveAction(CharSequence msg)422     void continueRemoveAction(CharSequence msg) {
423         if (!mWaitingForRemoveMsg) {
424             return;
425         }
426         mWaitingForRemoveMsg = false;
427         if (msg == null) {
428             try {
429                 ActivityManagerNative.getDefault().resumeAppSwitches();
430             } catch (RemoteException e) {
431             }
432             mDPM.removeActiveAdmin(mDeviceAdmin.getComponent());
433             finish();
434         } else {
435             try {
436                 // Continue preventing anything from coming in front.
437                 ActivityManagerNative.getDefault().stopAppSwitches();
438             } catch (RemoteException e) {
439             }
440             Bundle args = new Bundle();
441             args.putCharSequence(
442                     DeviceAdminReceiver.EXTRA_DISABLE_WARNING, msg);
443             showDialog(DIALOG_WARNING, args);
444         }
445     }
446 
447     @Override
onResume()448     protected void onResume() {
449         super.onResume();
450         updateInterface();
451         // As long as we are running, don't let this admin overlay stuff on top of the screen.
452         final int uid = mDeviceAdmin.getActivityInfo().applicationInfo.uid;
453         final String pkg = mDeviceAdmin.getActivityInfo().applicationInfo.packageName;
454         mCurSysAppOpMode = mAppOps.checkOp(AppOpsManager.OP_SYSTEM_ALERT_WINDOW, uid, pkg);
455         mCurToastAppOpMode = mAppOps.checkOp(AppOpsManager.OP_TOAST_WINDOW, uid, pkg);
456         mAppOps.setMode(AppOpsManager.OP_SYSTEM_ALERT_WINDOW, uid, pkg, AppOpsManager.MODE_IGNORED);
457         mAppOps.setMode(AppOpsManager.OP_TOAST_WINDOW, uid, pkg, AppOpsManager.MODE_IGNORED);
458     }
459 
460     @Override
onPause()461     protected void onPause() {
462         super.onPause();
463         // As long as we are running, don't let this admin overlay stuff on top of the screen.
464         final int uid = mDeviceAdmin.getActivityInfo().applicationInfo.uid;
465         final String pkg = mDeviceAdmin.getActivityInfo().applicationInfo.packageName;
466         mAppOps.setMode(AppOpsManager.OP_SYSTEM_ALERT_WINDOW, uid, pkg, mCurSysAppOpMode);
467         mAppOps.setMode(AppOpsManager.OP_TOAST_WINDOW, uid, pkg, mCurToastAppOpMode);
468         try {
469             ActivityManagerNative.getDefault().resumeAppSwitches();
470         } catch (RemoteException e) {
471         }
472     }
473 
474     @Override
onUserLeaveHint()475     protected void onUserLeaveHint() {
476         super.onUserLeaveHint();
477         // In case this is triggered from support dialog, finish this activity once the user leaves
478         // so that this won't appear as a background next time support dialog is triggered. This
479         // is because the support dialog activity and this belong to the same task and we can't
480         // start this in new activity since we need to know the calling package in this activity.
481         if (mIsCalledFromSupportDialog) {
482             finish();
483         }
484     }
485 
486     @Override
onCreateDialog(int id, Bundle args)487     protected Dialog onCreateDialog(int id, Bundle args) {
488         switch (id) {
489             case DIALOG_WARNING: {
490                 CharSequence msg = args.getCharSequence(DeviceAdminReceiver.EXTRA_DISABLE_WARNING);
491                 AlertDialog.Builder builder = new AlertDialog.Builder(this);
492                 builder.setMessage(msg);
493                 builder.setPositiveButton(R.string.dlg_ok,
494                         new DialogInterface.OnClickListener() {
495                     public void onClick(DialogInterface dialog, int which) {
496                         try {
497                             ActivityManagerNative.getDefault().resumeAppSwitches();
498                         } catch (RemoteException e) {
499                         }
500                         mDPM.removeActiveAdmin(mDeviceAdmin.getComponent());
501                         finish();
502                     }
503                 });
504                 builder.setNegativeButton(R.string.dlg_cancel, null);
505                 return builder.create();
506             }
507             default:
508                 return super.onCreateDialog(id, args);
509 
510         }
511     }
512 
updateInterface()513     void updateInterface() {
514         mAdminIcon.setImageDrawable(mDeviceAdmin.loadIcon(getPackageManager()));
515         mAdminName.setText(mDeviceAdmin.loadLabel(getPackageManager()));
516         try {
517             mAdminDescription.setText(
518                     mDeviceAdmin.loadDescription(getPackageManager()));
519             mAdminDescription.setVisibility(View.VISIBLE);
520         } catch (Resources.NotFoundException e) {
521             mAdminDescription.setVisibility(View.GONE);
522         }
523         if (mAddingProfileOwner) {
524             mProfileOwnerWarning.setVisibility(View.VISIBLE);
525         }
526         if (mAddMsgText != null) {
527             mAddMsg.setText(mAddMsgText);
528             mAddMsg.setVisibility(View.VISIBLE);
529         } else {
530             mAddMsg.setVisibility(View.GONE);
531             mAddMsgExpander.setVisibility(View.GONE);
532         }
533         if (!mRefreshing && !mAddingProfileOwner
534                 && mDPM.isAdminActive(mDeviceAdmin.getComponent())) {
535             mAdding = false;
536             final boolean isProfileOwner =
537                     mDeviceAdmin.getComponent().equals(mDPM.getProfileOwner());
538             final boolean isManagedProfile = isManagedProfile(mDeviceAdmin);
539             if (isProfileOwner && isManagedProfile) {
540                 // Profile owner in a managed profile, user can remove profile to disable admin.
541                 mAdminWarning.setText(R.string.admin_profile_owner_message);
542                 mActionButton.setText(R.string.remove_managed_profile_label);
543             } else if (isProfileOwner || mDeviceAdmin.getComponent().equals(
544                             mDPM.getDeviceOwnerComponentOnCallingUser())) {
545                 // Profile owner in a user or device owner, user can't disable admin.
546                 if (isProfileOwner) {
547                     // Show profile owner in a user description.
548                     mAdminWarning.setText(R.string.admin_profile_owner_user_message);
549                 } else {
550                     // Show device owner description.
551                     mAdminWarning.setText(R.string.admin_device_owner_message);
552                 }
553                 mActionButton.setText(R.string.remove_device_admin);
554                 mActionButton.setEnabled(false);
555             } else {
556                 addDeviceAdminPolicies(false /* showDescription */);
557                 mAdminWarning.setText(getString(R.string.device_admin_status,
558                         mDeviceAdmin.getActivityInfo().applicationInfo.loadLabel(
559                         getPackageManager())));
560                 setTitle(R.string.active_device_admin_msg);
561                 if (mUninstalling) {
562                     mActionButton.setText(R.string.remove_and_uninstall_device_admin);
563                 } else {
564                     mActionButton.setText(R.string.remove_device_admin);
565                 }
566             }
567             CharSequence supportMessage = mDPM.getLongSupportMessageForUser(
568                     mDeviceAdmin.getComponent(), UserHandle.myUserId());
569             if (!TextUtils.isEmpty(supportMessage)) {
570                 mSupportMessage.setText(supportMessage);
571                 mSupportMessage.setVisibility(View.VISIBLE);
572             } else {
573                 mSupportMessage.setVisibility(View.GONE);
574             }
575         } else {
576             addDeviceAdminPolicies(true /* showDescription */);
577             mAdminWarning.setText(getString(R.string.device_admin_warning,
578                     mDeviceAdmin.getActivityInfo().applicationInfo.loadLabel(getPackageManager())));
579             if (mAddingProfileOwner) {
580                 setTitle(getText(R.string.profile_owner_add_title));
581             } else {
582                 setTitle(getText(R.string.add_device_admin_msg));
583             }
584             mActionButton.setText(getText(R.string.add_device_admin));
585             if (isAdminUninstallable()) {
586                 mUninstallButton.setVisibility(View.VISIBLE);
587             }
588             mSupportMessage.setVisibility(View.GONE);
589             mAdding = true;
590         }
591     }
592 
addDeviceAdminPolicies(boolean showDescription)593     private void addDeviceAdminPolicies(boolean showDescription) {
594         if (!mAdminPoliciesInitialized) {
595             boolean isAdminUser = UserManager.get(this).isAdminUser();
596             for (DeviceAdminInfo.PolicyInfo pi : mDeviceAdmin.getUsedPolicies()) {
597                 int descriptionId = isAdminUser ? pi.description : pi.descriptionForSecondaryUsers;
598                 int labelId = isAdminUser ? pi.label : pi.labelForSecondaryUsers;
599                 View view = AppSecurityPermissions.getPermissionItemView(this, getText(labelId),
600                         showDescription ? getText(descriptionId) : "", true);
601                 mAdminPolicies.addView(view);
602             }
603             mAdminPoliciesInitialized = true;
604         }
605     }
606 
toggleMessageEllipsis(View v)607     void toggleMessageEllipsis(View v) {
608         TextView tv = (TextView) v;
609 
610         mAddMsgEllipsized = ! mAddMsgEllipsized;
611         tv.setEllipsize(mAddMsgEllipsized ? TruncateAt.END : null);
612         tv.setMaxLines(mAddMsgEllipsized ? getEllipsizedLines() : MAX_ADD_MSG_LINES);
613 
614         mAddMsgExpander.setImageResource(mAddMsgEllipsized ?
615             com.android.internal.R.drawable.expander_ic_minimized :
616             com.android.internal.R.drawable.expander_ic_maximized);
617     }
618 
getEllipsizedLines()619     int getEllipsizedLines() {
620         Display d = ((WindowManager) getSystemService(Context.WINDOW_SERVICE))
621                     .getDefaultDisplay();
622 
623         return d.getHeight() > d.getWidth() ?
624             MAX_ADD_MSG_LINES_PORTRAIT : MAX_ADD_MSG_LINES_LANDSCAPE;
625     }
626 
627     /**
628      * @return true if adminInfo is running in a managed profile.
629      */
isManagedProfile(DeviceAdminInfo adminInfo)630     private boolean isManagedProfile(DeviceAdminInfo adminInfo) {
631         UserManager um = UserManager.get(this);
632         UserInfo info = um.getUserInfo(
633                 UserHandle.getUserId(adminInfo.getActivityInfo().applicationInfo.uid));
634         return info != null ? info.isManagedProfile() : false;
635     }
636 
isAdminUninstallable()637     private boolean isAdminUninstallable() {
638         // System apps can't be uninstalled.
639         return !mDeviceAdmin.getActivityInfo().applicationInfo.isSystemApp();
640     }
641 }
642