1 /* 2 * Copyright (C) 2015 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.documentsui; 18 19 import static com.android.documentsui.Shared.DEBUG; 20 21 import android.app.Activity; 22 import android.app.ActivityManager; 23 import android.app.ActivityManager.AppTask; 24 import android.content.Context; 25 import android.content.Intent; 26 import android.net.Uri; 27 import android.os.Bundle; 28 import android.provider.DocumentsContract; 29 import android.support.annotation.Nullable; 30 import android.util.Log; 31 32 import java.util.List; 33 34 /** 35 * Provides FilesActivity task grouping support. This allows multiple FilesActivities to be 36 * launched (a behavior imparted by way of {@code documentLaunchMode="intoExisting"} and 37 * our use of pseudo document {@link Uri}s. This also lets us move an existing task 38 * to the foreground when a suitable task exists. 39 * 40 * Requires that {@code documentLaunchMode="intoExisting"} be set on target activity. 41 * 42 */ 43 public class LauncherActivity extends Activity { 44 45 private static final String LAUNCH_CONTROL_AUTHORITY = "com.android.documentsui.launchControl"; 46 private static final String TAG = "LauncherActivity"; 47 48 // Array of boolean extras that should be copied when creating new launch intents. 49 // Missing intents will be ignored. 50 private static final String[] PERSISTENT_BOOLEAN_EXTRAS = { 51 DocumentsContract.EXTRA_SHOW_FILESIZE, 52 DocumentsContract.EXTRA_SHOW_ADVANCED, 53 DocumentsContract.EXTRA_FANCY_FEATURES, 54 Shared.EXTRA_PRODUCTIVITY_MODE 55 }; 56 57 @Override onCreate(Bundle savedInstanceState)58 protected void onCreate(Bundle savedInstanceState) { 59 super.onCreate(savedInstanceState); 60 61 ActivityManager activities = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); 62 63 Intent intent = findTask(activities); 64 if (intent != null) { 65 restoreTask(intent); 66 } else { 67 startTask(); 68 } 69 70 finish(); 71 } 72 findTask(ActivityManager activities)73 private @Nullable Intent findTask(ActivityManager activities) { 74 List<AppTask> tasks = activities.getAppTasks(); 75 for (AppTask task : tasks) { 76 Intent intent = task.getTaskInfo().baseIntent; 77 Uri uri = intent.getData(); 78 if (isLaunchUri(uri)) { 79 return intent; 80 } 81 } 82 return null; 83 } 84 startTask()85 private void startTask() { 86 Intent intent = createLaunchIntent(this); 87 88 // Forward any flags from the original intent. 89 intent.setFlags(getIntent().getFlags()); 90 if (DEBUG) Log.d(TAG, "Starting new task > " + intent.getData()); 91 startActivity(intent); 92 } 93 restoreTask(Intent intent)94 private void restoreTask(Intent intent) { 95 if (DEBUG) Log.d(TAG, "Restoring existing task > " + intent.getData()); 96 // TODO: This doesn't appear to restore a task once it has stopped running. 97 startActivity(intent); 98 } 99 createLaunchIntent(Activity activity)100 static final Intent createLaunchIntent(Activity activity) { 101 Intent intent = new Intent(activity, FilesActivity.class); 102 intent.setData(buildLaunchUri()); 103 104 // Relay any config overrides bits present in the original intent. 105 Intent original = activity.getIntent(); 106 if (original != null) { 107 copyExtras(original, intent); 108 if (original.hasExtra(Intent.EXTRA_TITLE)) { 109 intent.putExtra( 110 Intent.EXTRA_TITLE, 111 original.getStringExtra(Intent.EXTRA_TITLE)); 112 } 113 } 114 return intent; 115 } 116 copyExtras(Intent src, Intent dest)117 private static void copyExtras(Intent src, Intent dest) { 118 for (String extra : PERSISTENT_BOOLEAN_EXTRAS) { 119 if (src.hasExtra(extra)) { 120 dest.putExtra(extra, src.getBooleanExtra(extra, false)); 121 } 122 } 123 } 124 buildLaunchUri()125 private static Uri buildLaunchUri() { 126 return new Uri.Builder() 127 .authority(LAUNCH_CONTROL_AUTHORITY) 128 .fragment(String.valueOf(System.currentTimeMillis())) 129 .build(); 130 } 131 isLaunchUri(@ullable Uri uri)132 static boolean isLaunchUri(@Nullable Uri uri) { 133 boolean result = uri != null && LAUNCH_CONTROL_AUTHORITY.equals(uri.getAuthority()); 134 return result; 135 } 136 } 137