1 /* 2 * Copyright (C) 2011 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.google.android.test.activity; 18 19 import java.util.ArrayList; 20 import java.util.List; 21 22 import android.app.Activity; 23 import android.app.ActivityManager; 24 import android.app.ActivityOptions; 25 import android.app.AlertDialog; 26 import android.content.ActivityNotFoundException; 27 import android.content.BroadcastReceiver; 28 import android.content.ComponentName; 29 import android.content.ContentProviderClient; 30 import android.content.Intent; 31 import android.content.ServiceConnection; 32 import android.graphics.BitmapFactory; 33 import android.os.Bundle; 34 import android.os.Handler; 35 import android.os.IBinder; 36 import android.os.Message; 37 import android.os.RemoteException; 38 import android.os.UserHandle; 39 import android.os.UserManager; 40 import android.graphics.Bitmap; 41 import android.widget.ImageView; 42 import android.widget.LinearLayout; 43 import android.widget.TextView; 44 import android.widget.ScrollView; 45 import android.widget.Toast; 46 import android.view.Menu; 47 import android.view.MenuItem; 48 import android.view.View; 49 import android.content.Context; 50 import android.content.pm.UserInfo; 51 import android.content.res.Configuration; 52 import android.util.Log; 53 54 public class ActivityTestMain extends Activity { 55 static final String TAG = "ActivityTest"; 56 57 static final String KEY_CONFIGURATION = "configuration"; 58 59 ActivityManager mAm; 60 Configuration mOverrideConfig; 61 int mSecondUser; 62 63 ArrayList<ServiceConnection> mConnections = new ArrayList<ServiceConnection>(); 64 65 ServiceConnection mIsolatedConnection; 66 67 static final int MSG_SPAM = 1; 68 69 final Handler mHandler = new Handler() { 70 @Override 71 public void handleMessage(Message msg) { 72 switch (msg.what) { 73 case MSG_SPAM: { 74 boolean fg = msg.arg1 != 0; 75 Intent intent = new Intent(ActivityTestMain.this, SpamActivity.class); 76 Bundle options = null; 77 if (fg) { 78 ActivityOptions opts = ActivityOptions.makeTaskLaunchBehind(); 79 options = opts.toBundle(); 80 } 81 startActivity(intent, options); 82 scheduleSpam(!fg); 83 } break; 84 } 85 super.handleMessage(msg); 86 } 87 }; 88 89 class BroadcastResultReceiver extends BroadcastReceiver { 90 @Override 91 public void onReceive(Context context, Intent intent) { 92 Bundle res = getResultExtras(true); 93 int user = res.getInt("user", -1); 94 Toast.makeText(ActivityTestMain.this, 95 "Receiver executed as user " 96 + (user >= 0 ? Integer.toString(user) : "unknown"), 97 Toast.LENGTH_LONG).show(); 98 } 99 } 100 101 private void addThumbnail(LinearLayout container, Bitmap bm, 102 final ActivityManager.RecentTaskInfo task, 103 final ActivityManager.TaskThumbnail thumbs) { 104 ImageView iv = new ImageView(this); 105 if (bm != null) { 106 iv.setImageBitmap(bm); 107 } 108 iv.setBackgroundResource(android.R.drawable.gallery_thumb); 109 int w = getResources().getDimensionPixelSize(android.R.dimen.thumbnail_width); 110 int h = getResources().getDimensionPixelSize(android.R.dimen.thumbnail_height); 111 container.addView(iv, new LinearLayout.LayoutParams(w, h)); 112 113 iv.setOnClickListener(new View.OnClickListener() { 114 @Override 115 public void onClick(View v) { 116 if (task.id >= 0 && thumbs != null) { 117 mAm.moveTaskToFront(task.id, ActivityManager.MOVE_TASK_WITH_HOME); 118 } else { 119 try { 120 startActivity(task.baseIntent); 121 } catch (ActivityNotFoundException e) { 122 Log.w("foo", "Unable to start task: " + e); 123 } 124 } 125 buildUi(); 126 } 127 }); 128 iv.setOnLongClickListener(new View.OnLongClickListener() { 129 @Override 130 public boolean onLongClick(View v) { 131 if (task.id >= 0 && thumbs != null) { 132 mAm.removeTask(task.id); 133 buildUi(); 134 return true; 135 } 136 return false; 137 } 138 }); 139 } 140 141 @Override 142 protected void onCreate(Bundle savedInstanceState) { 143 super.onCreate(savedInstanceState); 144 145 Log.i(TAG, "Referrer: " + getReferrer()); 146 147 mAm = (ActivityManager)getSystemService(ACTIVITY_SERVICE); 148 if (savedInstanceState != null) { 149 mOverrideConfig = savedInstanceState.getParcelable(KEY_CONFIGURATION); 150 if (mOverrideConfig != null) { 151 applyOverrideConfiguration(mOverrideConfig); 152 } 153 } 154 155 UserManager um = (UserManager)getSystemService(Context.USER_SERVICE); 156 List<UserInfo> users = um.getUsers(); 157 mSecondUser = Integer.MAX_VALUE; 158 for (UserInfo ui : users) { 159 if (ui.id != 0 && mSecondUser > ui.id) { 160 mSecondUser = ui.id; 161 } 162 } 163 164 /* 165 AlertDialog ad = new AlertDialog.Builder(this).setTitle("title").setMessage("message").create(); 166 ad.getWindow().getAttributes().type = WindowManager.LayoutParams.TYPE_SYSTEM_ERROR; 167 ad.show(); 168 */ 169 } 170 171 @Override 172 public boolean onCreateOptionsMenu(Menu menu) { 173 menu.add("Animate!").setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { 174 @Override 175 public boolean onMenuItemClick(MenuItem item) { 176 AlertDialog.Builder builder = new AlertDialog.Builder(ActivityTestMain.this, 177 R.style.SlowDialog); 178 builder.setTitle("This is a title"); 179 builder.show(); 180 return true; 181 } 182 }); 183 menu.add("Bind!").setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { 184 @Override public boolean onMenuItemClick(MenuItem item) { 185 Intent intent = new Intent(ActivityTestMain.this, SingleUserService.class); 186 ServiceConnection conn = new ServiceConnection() { 187 @Override 188 public void onServiceConnected(ComponentName name, IBinder service) { 189 Log.i(TAG, "Service connected " + name + " " + service); 190 } 191 @Override 192 public void onServiceDisconnected(ComponentName name) { 193 Log.i(TAG, "Service disconnected " + name); 194 } 195 }; 196 if (bindService(intent, conn, Context.BIND_AUTO_CREATE)) { 197 mConnections.add(conn); 198 } else { 199 Toast.makeText(ActivityTestMain.this, "Failed to bind", 200 Toast.LENGTH_LONG).show(); 201 } 202 return true; 203 } 204 }); 205 menu.add("Start!").setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { 206 @Override public boolean onMenuItemClick(MenuItem item) { 207 Intent intent = new Intent(ActivityTestMain.this, SingleUserService.class); 208 startService(intent); 209 return true; 210 } 211 }); 212 menu.add("Rebind Isolated!").setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { 213 @Override public boolean onMenuItemClick(MenuItem item) { 214 Intent intent = new Intent(ActivityTestMain.this, IsolatedService.class); 215 ServiceConnection conn = new ServiceConnection() { 216 @Override 217 public void onServiceConnected(ComponentName name, IBinder service) { 218 Log.i(TAG, "Isolated service connected " + name + " " + service); 219 } 220 @Override 221 public void onServiceDisconnected(ComponentName name) { 222 Log.i(TAG, "Isolated service disconnected " + name); 223 } 224 }; 225 if (mIsolatedConnection != null) { 226 Log.i(TAG, "Unbinding existing service: " + mIsolatedConnection); 227 unbindService(mIsolatedConnection); 228 mIsolatedConnection = null; 229 } 230 Log.i(TAG, "Binding new service: " + conn); 231 if (bindService(intent, conn, Context.BIND_AUTO_CREATE)) { 232 mIsolatedConnection = conn; 233 } else { 234 Toast.makeText(ActivityTestMain.this, "Failed to bind", 235 Toast.LENGTH_LONG).show(); 236 } 237 return true; 238 } 239 }); 240 menu.add("Send!").setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { 241 @Override public boolean onMenuItemClick(MenuItem item) { 242 Intent intent = new Intent(ActivityTestMain.this, SingleUserReceiver.class); 243 sendOrderedBroadcast(intent, null, new BroadcastResultReceiver(), 244 null, Activity.RESULT_OK, null, null); 245 return true; 246 } 247 }); 248 menu.add("Call!").setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { 249 @Override public boolean onMenuItemClick(MenuItem item) { 250 ContentProviderClient cpl = getContentResolver().acquireContentProviderClient( 251 SingleUserProvider.AUTHORITY); 252 Bundle res = null; 253 try { 254 res = cpl.call("getuser", null, null); 255 } catch (RemoteException e) { 256 } 257 int user = res != null ? res.getInt("user", -1) : -1; 258 Toast.makeText(ActivityTestMain.this, 259 "Provider executed as user " 260 + (user >= 0 ? Integer.toString(user) : "unknown"), 261 Toast.LENGTH_LONG).show(); 262 cpl.release(); 263 return true; 264 } 265 }); 266 menu.add("Send to user 0!").setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { 267 @Override public boolean onMenuItemClick(MenuItem item) { 268 Intent intent = new Intent(ActivityTestMain.this, UserTarget.class); 269 sendOrderedBroadcastAsUser(intent, new UserHandle(0), null, 270 new BroadcastResultReceiver(), 271 null, Activity.RESULT_OK, null, null); 272 return true; 273 } 274 }); 275 menu.add("Send to user " + mSecondUser + "!").setOnMenuItemClickListener( 276 new MenuItem.OnMenuItemClickListener() { 277 @Override public boolean onMenuItemClick(MenuItem item) { 278 Intent intent = new Intent(ActivityTestMain.this, UserTarget.class); 279 sendOrderedBroadcastAsUser(intent, new UserHandle(mSecondUser), null, 280 new BroadcastResultReceiver(), 281 null, Activity.RESULT_OK, null, null); 282 return true; 283 } 284 }); 285 menu.add("Bind to user 0!").setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { 286 @Override public boolean onMenuItemClick(MenuItem item) { 287 Intent intent = new Intent(ActivityTestMain.this, ServiceUserTarget.class); 288 ServiceConnection conn = new ServiceConnection() { 289 @Override 290 public void onServiceConnected(ComponentName name, IBinder service) { 291 Log.i(TAG, "Service connected " + name + " " + service); 292 } 293 @Override 294 public void onServiceDisconnected(ComponentName name) { 295 Log.i(TAG, "Service disconnected " + name); 296 } 297 }; 298 if (bindServiceAsUser(intent, conn, Context.BIND_AUTO_CREATE, UserHandle.OWNER)) { 299 mConnections.add(conn); 300 } else { 301 Toast.makeText(ActivityTestMain.this, "Failed to bind", 302 Toast.LENGTH_LONG).show(); 303 } 304 return true; 305 } 306 }); 307 menu.add("Bind to user " + mSecondUser + "!").setOnMenuItemClickListener( 308 new MenuItem.OnMenuItemClickListener() { 309 @Override public boolean onMenuItemClick(MenuItem item) { 310 Intent intent = new Intent(ActivityTestMain.this, ServiceUserTarget.class); 311 ServiceConnection conn = new ServiceConnection() { 312 @Override 313 public void onServiceConnected(ComponentName name, IBinder service) { 314 Log.i(TAG, "Service connected " + name + " " + service); 315 } 316 @Override 317 public void onServiceDisconnected(ComponentName name) { 318 Log.i(TAG, "Service disconnected " + name); 319 } 320 }; 321 if (bindServiceAsUser(intent, conn, Context.BIND_AUTO_CREATE, 322 new UserHandle(mSecondUser))) { 323 mConnections.add(conn); 324 } else { 325 Toast.makeText(ActivityTestMain.this, "Failed to bind", 326 Toast.LENGTH_LONG).show(); 327 } 328 return true; 329 } 330 }); 331 menu.add("Density!").setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { 332 @Override public boolean onMenuItemClick(MenuItem item) { 333 if (mOverrideConfig == null) { 334 mOverrideConfig = new Configuration(); 335 } 336 if (mOverrideConfig.densityDpi == Configuration.DENSITY_DPI_UNDEFINED) { 337 mOverrideConfig.densityDpi = (getApplicationContext().getResources() 338 .getConfiguration().densityDpi*2)/3; 339 } else { 340 mOverrideConfig.densityDpi = Configuration.DENSITY_DPI_UNDEFINED; 341 } 342 recreate(); 343 return true; 344 } 345 }); 346 menu.add("HashArray").setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { 347 @Override public boolean onMenuItemClick(MenuItem item) { 348 ArrayMapTests.run(); 349 return true; 350 } 351 }); 352 menu.add("Add App Recent").setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { 353 @Override public boolean onMenuItemClick(MenuItem item) { 354 addAppRecents(1); 355 return true; 356 } 357 }); 358 menu.add("Add App 10x Recent").setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { 359 @Override public boolean onMenuItemClick(MenuItem item) { 360 addAppRecents(10); 361 return true; 362 } 363 }); 364 menu.add("Exclude!").setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { 365 @Override public boolean onMenuItemClick(MenuItem item) { 366 setExclude(true); 367 return true; 368 } 369 }); 370 menu.add("Include!").setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { 371 @Override public boolean onMenuItemClick(MenuItem item) { 372 setExclude(false); 373 return true; 374 } 375 }); 376 menu.add("Open Doc").setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { 377 @Override public boolean onMenuItemClick(MenuItem item) { 378 ActivityManager.AppTask task = findDocTask(); 379 if (task == null) { 380 Intent intent = new Intent(ActivityTestMain.this, DocActivity.class); 381 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT 382 | Intent.FLAG_ACTIVITY_MULTIPLE_TASK 383 | Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS); 384 startActivity(intent); 385 } else { 386 task.moveToFront(); 387 } 388 return true; 389 } 390 }); 391 menu.add("Stack Doc").setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { 392 @Override public boolean onMenuItemClick(MenuItem item) { 393 ActivityManager.AppTask task = findDocTask(); 394 if (task != null) { 395 ActivityManager.RecentTaskInfo recent = task.getTaskInfo(); 396 Intent intent = new Intent(ActivityTestMain.this, DocActivity.class); 397 if (recent.id >= 0) { 398 // Stack on top. 399 intent.putExtra(DocActivity.LABEL, "Stacked"); 400 } else { 401 // Start root activity. 402 intent.putExtra(DocActivity.LABEL, "New Root"); 403 } 404 task.startActivity(ActivityTestMain.this, intent, null); 405 } 406 return true; 407 } 408 }); 409 menu.add("Spam!").setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { 410 @Override public boolean onMenuItemClick(MenuItem item) { 411 scheduleSpam(false); 412 return true; 413 } 414 }); 415 return true; 416 } 417 418 @Override 419 protected void onStart() { 420 super.onStart(); 421 buildUi(); 422 } 423 424 @Override 425 protected void onPause() { 426 super.onPause(); 427 Log.i(TAG, "I'm such a slooow poor loser"); 428 try { 429 Thread.sleep(500); 430 } catch (InterruptedException e) { 431 } 432 Log.i(TAG, "See?"); 433 } 434 435 @Override 436 protected void onSaveInstanceState(Bundle outState) { 437 super.onSaveInstanceState(outState); 438 if (mOverrideConfig != null) { 439 outState.putParcelable(KEY_CONFIGURATION, mOverrideConfig); 440 } 441 } 442 443 @Override 444 protected void onStop() { 445 super.onStop(); 446 for (ServiceConnection conn : mConnections) { 447 unbindService(conn); 448 } 449 mConnections.clear(); 450 if (mIsolatedConnection != null) { 451 unbindService(mIsolatedConnection); 452 mIsolatedConnection = null; 453 } 454 } 455 456 @Override 457 protected void onDestroy() { 458 super.onDestroy(); 459 mHandler.removeMessages(MSG_SPAM); 460 } 461 462 void addAppRecents(int count) { 463 ActivityManager am = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE); 464 Intent intent = new Intent(Intent.ACTION_MAIN); 465 intent.addCategory(Intent.CATEGORY_LAUNCHER); 466 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT); 467 intent.setComponent(new ComponentName(this, ActivityTestMain.class)); 468 for (int i=0; i<count; i++) { 469 ActivityManager.TaskDescription desc = new ActivityManager.TaskDescription(); 470 desc.setLabel("Added #" + i); 471 Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.icon); 472 if ((i&1) == 0) { 473 desc.setIcon(bitmap); 474 } 475 int taskId = am.addAppTask(this, intent, desc, bitmap); 476 Log.i(TAG, "Added new task id #" + taskId); 477 } 478 } 479 480 void setExclude(boolean exclude) { 481 ActivityManager am = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE); 482 List<ActivityManager.AppTask> tasks = am.getAppTasks(); 483 int taskId = getTaskId(); 484 for (int i=0; i<tasks.size(); i++) { 485 ActivityManager.AppTask task = tasks.get(i); 486 if (task.getTaskInfo().id == taskId) { 487 task.setExcludeFromRecents(exclude); 488 } 489 } 490 } 491 492 ActivityManager.AppTask findDocTask() { 493 ActivityManager am = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE); 494 List<ActivityManager.AppTask> tasks = am.getAppTasks(); 495 if (tasks != null) { 496 for (int i=0; i<tasks.size(); i++) { 497 ActivityManager.AppTask task = tasks.get(i); 498 ActivityManager.RecentTaskInfo recent = task.getTaskInfo(); 499 if (recent.baseIntent != null 500 && recent.baseIntent.getComponent().getClassName().equals( 501 DocActivity.class.getCanonicalName())) { 502 return task; 503 } 504 } 505 } 506 return null; 507 } 508 509 void scheduleSpam(boolean fg) { 510 mHandler.removeMessages(MSG_SPAM); 511 Message msg = mHandler.obtainMessage(MSG_SPAM, fg ? 1 : 0, 0); 512 mHandler.sendMessageDelayed(msg, 500); 513 } 514 515 private View scrollWrap(View view) { 516 ScrollView scroller = new ScrollView(this); 517 scroller.addView(view, new ScrollView.LayoutParams(ScrollView.LayoutParams.MATCH_PARENT, 518 ScrollView.LayoutParams.MATCH_PARENT)); 519 return scroller; 520 } 521 522 private void buildUi() { 523 LinearLayout top = new LinearLayout(this); 524 top.setOrientation(LinearLayout.VERTICAL); 525 526 List<ActivityManager.RecentTaskInfo> recents = mAm.getRecentTasks(10, 527 ActivityManager.RECENT_WITH_EXCLUDED); 528 if (recents != null) { 529 for (int i=0; i<recents.size(); i++) { 530 ActivityManager.RecentTaskInfo r = recents.get(i); 531 ActivityManager.TaskThumbnail tt = mAm.getTaskThumbnail(r.persistentId); 532 TextView tv = new TextView(this); 533 tv.setText(r.baseIntent.getComponent().flattenToShortString()); 534 top.addView(tv, new LinearLayout.LayoutParams( 535 LinearLayout.LayoutParams.WRAP_CONTENT, 536 LinearLayout.LayoutParams.WRAP_CONTENT)); 537 LinearLayout item = new LinearLayout(this); 538 item.setOrientation(LinearLayout.HORIZONTAL); 539 addThumbnail(item, tt != null ? tt.mainThumbnail : null, r, tt); 540 top.addView(item, new LinearLayout.LayoutParams( 541 LinearLayout.LayoutParams.WRAP_CONTENT, 542 LinearLayout.LayoutParams.WRAP_CONTENT)); 543 } 544 } 545 546 setContentView(scrollWrap(top)); 547 } 548 } 549