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 // When activating, make sure the given component name is actually a valid device admin. 120 // No need to check this when deactivating, because it is safe to deactivate an active 121 // invalid device admin. 122 if (!mDPM.isAdminActive(cn)) { 123 List<ResolveInfo> avail = getPackageManager().queryBroadcastReceivers( 124 new Intent(DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED), 125 PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS); 126 int count = avail == null ? 0 : avail.size(); 127 boolean found = false; 128 for (int i=0; i<count; i++) { 129 ResolveInfo ri = avail.get(i); 130 if (ai.packageName.equals(ri.activityInfo.packageName) 131 && ai.name.equals(ri.activityInfo.name)) { 132 try { 133 // We didn't retrieve the meta data for all possible matches, so 134 // need to use the activity info of this specific one that was retrieved. 135 ri.activityInfo = ai; 136 DeviceAdminInfo dpi = new DeviceAdminInfo(this, ri); 137 found = true; 138 } catch (XmlPullParserException e) { 139 Log.w(TAG, "Bad " + ri.activityInfo, e); 140 } catch (IOException e) { 141 Log.w(TAG, "Bad " + ri.activityInfo, e); 142 } 143 break; 144 } 145 } 146 if (!found) { 147 Log.w(TAG, "Request to add invalid device admin: " + cn); 148 finish(); 149 return; 150 } 151 } 152 153 ResolveInfo ri = new ResolveInfo(); 154 ri.activityInfo = ai; 155 try { 156 mDeviceAdmin = new DeviceAdminInfo(this, ri); 157 } catch (XmlPullParserException e) { 158 Log.w(TAG, "Unable to retrieve device policy " + cn, e); 159 finish(); 160 return; 161 } catch (IOException e) { 162 Log.w(TAG, "Unable to retrieve device policy " + cn, e); 163 finish(); 164 return; 165 } 166 167 // This admin already exists, an we have two options at this point. If new policy 168 // bits are set, show the user the new list. If nothing has changed, simply return 169 // "OK" immediately. 170 if (DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN.equals(getIntent().getAction())) { 171 mRefreshing = false; 172 if (mDPM.isAdminActive(cn)) { 173 ArrayList<DeviceAdminInfo.PolicyInfo> newPolicies = mDeviceAdmin.getUsedPolicies(); 174 for (int i = 0; i < newPolicies.size(); i++) { 175 DeviceAdminInfo.PolicyInfo pi = newPolicies.get(i); 176 if (!mDPM.hasGrantedPolicy(cn, pi.ident)) { 177 mRefreshing = true; 178 break; 179 } 180 } 181 if (!mRefreshing) { 182 // Nothing changed (or policies were removed) - return immediately 183 setResult(Activity.RESULT_OK); 184 finish(); 185 return; 186 } 187 } 188 } 189 mAddMsgText = getIntent().getCharSequenceExtra(DevicePolicyManager.EXTRA_ADD_EXPLANATION); 190 191 setContentView(R.layout.device_admin_add); 192 193 mAdminIcon = (ImageView)findViewById(R.id.admin_icon); 194 mAdminName = (TextView)findViewById(R.id.admin_name); 195 mAdminDescription = (TextView)findViewById(R.id.admin_description); 196 197 mAddMsg = (TextView)findViewById(R.id.add_msg); 198 mAddMsgExpander = (ImageView) findViewById(R.id.add_msg_expander); 199 mAddMsg.setOnClickListener(new View.OnClickListener() { 200 public void onClick(View v) { 201 toggleMessageEllipsis(v); 202 } 203 }); 204 205 // toggleMessageEllipsis also handles initial layout: 206 toggleMessageEllipsis(mAddMsg); 207 208 mAdminWarning = (TextView) findViewById(R.id.admin_warning); 209 mAdminPolicies = (ViewGroup) findViewById(R.id.admin_policies); 210 mCancelButton = (Button) findViewById(R.id.cancel_button); 211 mCancelButton.setOnClickListener(new View.OnClickListener() { 212 public void onClick(View v) { 213 finish(); 214 } 215 }); 216 mActionButton = (Button) findViewById(R.id.action_button); 217 mActionButton.setOnClickListener(new View.OnClickListener() { 218 public void onClick(View v) { 219 if (mAdding) { 220 try { 221 mDPM.setActiveAdmin(mDeviceAdmin.getComponent(), mRefreshing); 222 setResult(Activity.RESULT_OK); 223 } catch (RuntimeException e) { 224 // Something bad happened... could be that it was 225 // already set, though. 226 Log.w(TAG, "Exception trying to activate admin " 227 + mDeviceAdmin.getComponent(), e); 228 if (mDPM.isAdminActive(mDeviceAdmin.getComponent())) { 229 setResult(Activity.RESULT_OK); 230 } 231 } 232 finish(); 233 } else { 234 try { 235 // Don't allow the admin to put a dialog up in front 236 // of us while we interact with the user. 237 ActivityManagerNative.getDefault().stopAppSwitches(); 238 } catch (RemoteException e) { 239 } 240 mDPM.getRemoveWarning(mDeviceAdmin.getComponent(), 241 new RemoteCallback(mHandler) { 242 @Override 243 protected void onResult(Bundle bundle) { 244 CharSequence msg = bundle != null 245 ? bundle.getCharSequence( 246 DeviceAdminReceiver.EXTRA_DISABLE_WARNING) 247 : null; 248 if (msg == null) { 249 try { 250 ActivityManagerNative.getDefault().resumeAppSwitches(); 251 } catch (RemoteException e) { 252 } 253 mDPM.removeActiveAdmin(mDeviceAdmin.getComponent()); 254 finish(); 255 } else { 256 Bundle args = new Bundle(); 257 args.putCharSequence( 258 DeviceAdminReceiver.EXTRA_DISABLE_WARNING, msg); 259 showDialog(DIALOG_WARNING, args); 260 } 261 } 262 }); 263 } 264 } 265 }); 266 } 267 268 @Override 269 protected void onResume() { 270 super.onResume(); 271 updateInterface(); 272 } 273 274 @Override 275 protected Dialog onCreateDialog(int id, Bundle args) { 276 switch (id) { 277 case DIALOG_WARNING: { 278 CharSequence msg = args.getCharSequence(DeviceAdminReceiver.EXTRA_DISABLE_WARNING); 279 AlertDialog.Builder builder = new AlertDialog.Builder( 280 DeviceAdminAdd.this); 281 builder.setMessage(msg); 282 builder.setPositiveButton(R.string.dlg_ok, 283 new DialogInterface.OnClickListener() { 284 public void onClick(DialogInterface dialog, int which) { 285 mDPM.removeActiveAdmin(mDeviceAdmin.getComponent()); 286 finish(); 287 } 288 }); 289 builder.setNegativeButton(R.string.dlg_cancel, null); 290 return builder.create(); 291 } 292 default: 293 return super.onCreateDialog(id, args); 294 295 } 296 } 297 298 static void setViewVisibility(ArrayList<View> views, int visibility) { 299 final int N = views.size(); 300 for (int i=0; i<N; i++) { 301 views.get(i).setVisibility(visibility); 302 } 303 } 304 305 void updateInterface() { 306 mAdminIcon.setImageDrawable(mDeviceAdmin.loadIcon(getPackageManager())); 307 mAdminName.setText(mDeviceAdmin.loadLabel(getPackageManager())); 308 try { 309 mAdminDescription.setText( 310 mDeviceAdmin.loadDescription(getPackageManager())); 311 mAdminDescription.setVisibility(View.VISIBLE); 312 } catch (Resources.NotFoundException e) { 313 mAdminDescription.setVisibility(View.GONE); 314 } 315 if (mAddMsgText != null) { 316 mAddMsg.setText(mAddMsgText); 317 mAddMsg.setVisibility(View.VISIBLE); 318 } else { 319 mAddMsg.setVisibility(View.GONE); 320 mAddMsgExpander.setVisibility(View.GONE); 321 } 322 if (!mRefreshing && mDPM.isAdminActive(mDeviceAdmin.getComponent())) { 323 if (mActivePolicies.size() == 0) { 324 ArrayList<DeviceAdminInfo.PolicyInfo> policies = mDeviceAdmin.getUsedPolicies(); 325 for (int i=0; i<policies.size(); i++) { 326 DeviceAdminInfo.PolicyInfo pi = policies.get(i); 327 View view = AppSecurityPermissions.getPermissionItemView( 328 this, getText(pi.label), "", true); 329 mActivePolicies.add(view); 330 mAdminPolicies.addView(view); 331 } 332 } 333 setViewVisibility(mActivePolicies, View.VISIBLE); 334 setViewVisibility(mAddingPolicies, View.GONE); 335 mAdminWarning.setText(getString(R.string.device_admin_status, 336 mDeviceAdmin.getActivityInfo().applicationInfo.loadLabel(getPackageManager()))); 337 setTitle(getText(R.string.active_device_admin_msg)); 338 mActionButton.setText(getText(R.string.remove_device_admin)); 339 mAdding = false; 340 } else { 341 if (mAddingPolicies.size() == 0) { 342 ArrayList<DeviceAdminInfo.PolicyInfo> policies = mDeviceAdmin.getUsedPolicies(); 343 for (int i=0; i<policies.size(); i++) { 344 DeviceAdminInfo.PolicyInfo pi = policies.get(i); 345 View view = AppSecurityPermissions.getPermissionItemView( 346 this, getText(pi.label), getText(pi.description), true); 347 mAddingPolicies.add(view); 348 mAdminPolicies.addView(view); 349 } 350 } 351 setViewVisibility(mAddingPolicies, View.VISIBLE); 352 setViewVisibility(mActivePolicies, View.GONE); 353 mAdminWarning.setText(getString(R.string.device_admin_warning, 354 mDeviceAdmin.getActivityInfo().applicationInfo.loadLabel(getPackageManager()))); 355 setTitle(getText(R.string.add_device_admin_msg)); 356 mActionButton.setText(getText(R.string.add_device_admin)); 357 mAdding = true; 358 } 359 } 360 361 362 void toggleMessageEllipsis(View v) { 363 TextView tv = (TextView) v; 364 365 mAddMsgEllipsized = ! mAddMsgEllipsized; 366 tv.setEllipsize(mAddMsgEllipsized ? TruncateAt.END : null); 367 tv.setMaxLines(mAddMsgEllipsized ? getEllipsizedLines() : MAX_ADD_MSG_LINES); 368 369 mAddMsgExpander.setImageResource(mAddMsgEllipsized ? 370 com.android.internal.R.drawable.expander_ic_minimized : 371 com.android.internal.R.drawable.expander_ic_maximized); 372 } 373 374 int getEllipsizedLines() { 375 Display d = ((WindowManager) getSystemService(Context.WINDOW_SERVICE)) 376 .getDefaultDisplay(); 377 378 return d.getHeight() > d.getWidth() ? 379 MAX_ADD_MSG_LINES_PORTRAIT : MAX_ADD_MSG_LINES_LANDSCAPE; 380 } 381 382 } 383