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