1 /* 2 * Copyright (C) 2013 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.cts.verifier.security; 18 19 import android.app.Service; 20 import android.app.admin.DevicePolicyManager; 21 import android.content.ActivityNotFoundException; 22 import android.content.Intent; 23 import android.os.Bundle; 24 import android.os.IBinder; 25 import android.util.Log; 26 import android.view.LayoutInflater; 27 import android.view.View; 28 import android.view.View.OnClickListener; 29 import android.view.ViewGroup; 30 import android.widget.Button; 31 import android.widget.ImageView; 32 import android.widget.TextView; 33 34 import com.android.cts.verifier.PassFailButtons; 35 import com.android.cts.verifier.R; 36 37 import java.io.File; 38 import java.io.FileOutputStream; 39 import java.io.IOException; 40 import java.io.InputStream; 41 import java.util.concurrent.LinkedBlockingQueue; 42 43 public class CAInstallNotificationVerifierActivity extends PassFailButtons.Activity 44 implements Runnable { 45 static final String TAG = CAInstallNotificationVerifierActivity.class.getSimpleName(); 46 private static final String STATE = "state"; 47 private static final int PASS = 1; 48 private static final int FAIL = 2; 49 private static final int WAIT_FOR_USER = 3; 50 private static LinkedBlockingQueue<String> sDeletedQueue = new LinkedBlockingQueue<String>(); 51 52 private int mState; 53 private int[] mStatus; 54 private LayoutInflater mInflater; 55 private ViewGroup mItemList; 56 private Runnable mRunner; 57 private View mHandler; 58 59 private static final String CERT_ASSET_NAME = "myCA.cer"; 60 private File certStagingFile = new File("/sdcard/", CERT_ASSET_NAME); 61 62 protected boolean doneInstallingCert = false; 63 protected boolean doneCheckingInSettings = false; 64 protected boolean doneRemovingScreenLock = false; 65 protected boolean doneCheckingNotification = false; 66 protected boolean doneDismissingNotification = false; 67 68 69 public static class DismissService extends Service { 70 @Override onBind(Intent intent)71 public IBinder onBind(Intent intent) { 72 return null; 73 } 74 75 @Override onStart(Intent intent, int startId)76 public void onStart(Intent intent, int startId) { 77 sDeletedQueue.offer(intent.getAction()); 78 } 79 } 80 81 @Override onCreate(Bundle savedInstanceState)82 protected void onCreate(Bundle savedInstanceState) { 83 super.onCreate(savedInstanceState); 84 85 if (savedInstanceState != null) { 86 mState = savedInstanceState.getInt(STATE, 0); 87 } 88 mRunner = this; 89 mInflater = getLayoutInflater(); 90 View view = mInflater.inflate(R.layout.cainstallnotify_main, null); 91 mItemList = (ViewGroup) view.findViewById(R.id.ca_notify_test_items); 92 mHandler = mItemList; 93 createTestItems(); 94 mStatus = new int[mItemList.getChildCount()]; 95 setContentView(view); 96 97 setPassFailButtonClickListeners(); 98 setInfoResources(R.string.cacert_test, R.string.cacert_info, -1); 99 } 100 101 @Override onSaveInstanceState(Bundle outState)102 protected void onSaveInstanceState (Bundle outState) { 103 outState.putInt(STATE, mState); 104 } 105 106 @Override onResume()107 protected void onResume() { 108 super.onResume(); 109 next(); 110 } 111 112 // Interface Utilities 113 createTestItems()114 private void createTestItems() { 115 createUserItem(R.string.cacert_install_cert, new InstallCert()); 116 createUserItem(R.string.cacert_check_cert_in_settings, new OpenTrustedCredentials()); 117 createUserItem(R.string.cacert_remove_screen_lock, new RemoveScreenLock()); 118 createUserItem(R.string.cacert_check_notification, 119 new DoneCheckingNotification(), R.string.cacert_done); 120 createUserItem(R.string.cacert_dismiss_notification, 121 new DoneCheckingDismissed(), R.string.cacert_done); 122 } 123 setItemState(int index, boolean passed)124 private void setItemState(int index, boolean passed) { 125 ViewGroup item = (ViewGroup) mItemList.getChildAt(index); 126 ImageView status = (ImageView) item.findViewById(R.id.ca_notify_status); 127 status.setImageResource(passed ? R.drawable.fs_good : R.drawable.fs_error); 128 View button = item.findViewById(R.id.ca_notify_do_something); 129 button.setClickable(false); 130 button.setEnabled(false); 131 status.invalidate(); 132 } 133 markItemWaiting(int index)134 private void markItemWaiting(int index) { 135 ViewGroup item = (ViewGroup) mItemList.getChildAt(index); 136 ImageView status = (ImageView) item.findViewById(R.id.ca_notify_status); 137 status.setImageResource(R.drawable.fs_warning); 138 status.invalidate(); 139 } 140 createUserItem(int stringId, OnClickListener listener)141 private View createUserItem(int stringId, OnClickListener listener) { 142 return createUserItem(stringId, listener, 0); 143 } 144 createUserItem(int stringId, OnClickListener listener, int buttonLabel)145 private View createUserItem(int stringId, OnClickListener listener, int buttonLabel) { 146 View item = mInflater.inflate(R.layout.cainstallnotify_item, mItemList, false); 147 TextView instructions = (TextView) item.findViewById(R.id.ca_notify_instructions); 148 instructions.setText(stringId); 149 Button button = (Button) item.findViewById(R.id.ca_notify_do_something); 150 if (buttonLabel != 0) { 151 button.setText(buttonLabel); 152 } 153 button.setOnClickListener(listener); 154 mItemList.addView(item); 155 return item; 156 } 157 158 // Test management 159 run()160 public void run() { 161 while (mState < mStatus.length && mStatus[mState] != WAIT_FOR_USER) { 162 if (mStatus[mState] == PASS) { 163 setItemState(mState, true); 164 mState++; 165 } else if (mStatus[mState] == FAIL) { 166 setItemState(mState, false); 167 return; 168 } else { 169 break; 170 } 171 } 172 173 if (mState < mStatus.length && mStatus[mState] == WAIT_FOR_USER) { 174 markItemWaiting(mState); 175 } 176 177 switch (mState) { 178 case 0: 179 testInstalledCert(0); 180 break; 181 case 1: 182 testCheckedSettings(1); 183 break; 184 case 2: 185 testRemovedScreenLock(2); 186 break; 187 case 3: 188 testCheckedNotification(3); 189 break; 190 case 4: 191 testNotificationDismissed(4); 192 break; 193 } 194 } 195 196 /** 197 * Return to the state machine to progress through the tests. 198 */ next()199 private void next() { 200 mHandler.post(mRunner); 201 } 202 203 /** 204 * Wait for things to settle before returning to the state machine. 205 */ delay()206 private void delay() { 207 mHandler.postDelayed(mRunner, 2000); 208 } 209 210 // Listeners 211 212 class InstallCert implements OnClickListener { 213 @Override onClick(View v)214 public void onClick(View v) { 215 InputStream is = null; 216 FileOutputStream os = null; 217 try { 218 try { 219 is = getAssets().open(CERT_ASSET_NAME); 220 os = new FileOutputStream(certStagingFile); 221 byte[] buffer = new byte[1024]; 222 int length; 223 while ((length = is.read(buffer)) > 0) { 224 os.write(buffer, 0, length); 225 } 226 } finally { 227 if (is != null) is.close(); 228 if (os != null) os.close(); 229 certStagingFile.setReadable(true, false); 230 } 231 } catch (IOException ioe) { 232 Log.w(TAG, "Problem moving cert file to /sdcard/", ioe); 233 return; 234 } 235 try { 236 startActivity(new Intent("android.credentials.INSTALL")); 237 } catch (ActivityNotFoundException e) { 238 // do nothing 239 } 240 doneInstallingCert = true; 241 } 242 } 243 244 class OpenTrustedCredentials implements OnClickListener { 245 @Override onClick(View v)246 public void onClick(View v) { 247 try { 248 startActivity(new Intent("com.android.settings.TRUSTED_CREDENTIALS_USER")); 249 } catch (ActivityNotFoundException e) { 250 // do nothing 251 } 252 doneCheckingInSettings = true; 253 } 254 } 255 256 class RemoveScreenLock implements OnClickListener { 257 @Override onClick(View v)258 public void onClick(View v) { 259 try { 260 startActivity(new Intent(DevicePolicyManager.ACTION_SET_NEW_PASSWORD)); 261 } catch (ActivityNotFoundException e) { 262 Log.w(TAG, "Activity not found for ACTION_SET_NEW_PASSWORD"); 263 } 264 doneRemovingScreenLock = true; 265 } 266 } 267 268 class DoneCheckingNotification implements OnClickListener { 269 @Override onClick(View v)270 public void onClick(View v) { 271 doneCheckingNotification = true; 272 } 273 } 274 275 class DoneCheckingDismissed implements OnClickListener { 276 @Override onClick(View v)277 public void onClick(View v) { 278 doneDismissingNotification = true; 279 } 280 } 281 282 // Tests 283 testInstalledCert(final int i)284 private void testInstalledCert(final int i) { 285 if (doneInstallingCert) { 286 mStatus[i] = PASS; 287 next(); 288 } else { 289 delay(); 290 } 291 } 292 testCheckedSettings(final int i)293 private void testCheckedSettings(final int i) { 294 if (doneCheckingInSettings) { 295 mStatus[i] = PASS; 296 next(); 297 } else { 298 delay(); 299 } 300 } 301 testRemovedScreenLock(final int i)302 private void testRemovedScreenLock(final int i) { 303 if (doneRemovingScreenLock) { 304 mStatus[i] = PASS; 305 next(); 306 } else { 307 delay(); 308 } 309 } 310 testCheckedNotification(final int i)311 private void testCheckedNotification(final int i) { 312 if (doneCheckingNotification) { 313 mStatus[i] = PASS; 314 next(); 315 } else { 316 delay(); 317 } 318 } 319 testNotificationDismissed(final int i)320 private void testNotificationDismissed(final int i) { 321 if (doneDismissingNotification) { 322 mStatus[i] = PASS; 323 next(); 324 } else { 325 delay(); 326 } 327 } 328 } 329