/* * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.example.android.intentplayground; import static java.util.Collections.singletonList; import android.app.TaskStackBuilder; import android.content.Context; import android.content.Intent; import android.util.Log; import java.util.ArrayList; import java.util.Arrays; import java.util.LinkedList; import java.util.List; /** * TestBase holds methods to query, test and compare task hierarchies. */ public class TestBase { static final String TAG = "TestBase"; private List mBuilders; private Context mContext; TestBase(Context context, Node hierarchy) { mBuilders = new LinkedList<>(); mContext = context; setActivities(hierarchy); } /** * Launch the activities specified by the constructor. * * @param style An enum that chooses which method to use to launch the activities. */ void startActivities(LaunchStyle style) { switch (style) { // COMMAND_LINE will only work if the application is installed with system permissions // that allow it to use am shell command "am start ..." case COMMAND_LINE: mBuilders.forEach(tsb -> Arrays.stream(tsb.getIntents()) .forEach(AMControl::launchInBackground)); break; case TASK_STACK_BUILDER: mBuilders.forEach(tsb -> { // TODO: does this indicate bug in ActivityManager? // The launch of each activity needs to be delayed a bit or ActivityManager will7 // skip creating most of them try { Thread.sleep(500); tsb.startActivities(); Thread.sleep(500); } catch (InterruptedException ie) { Log.e(TAG, ie.getMessage()); } }); break; case LAUNCH_FORWARD: mBuilders.forEach(tsb -> { // The launch of each activity needs to be delayed a bit or ActivityManager will // skip creating most of them try { Thread.sleep(500); } catch (InterruptedException ie) { Log.e(TAG, ie.getMessage()); } ArrayList nextIntents = new ArrayList<>(Arrays.asList( tsb.getIntents())); Intent launch = nextIntents.remove(0) .putParcelableArrayListExtra(BaseActivity.EXTRA_LAUNCH_FORWARD, nextIntents); if (BuildConfig.DEBUG) { Log.d(TAG, "Launching " + launch.getComponent().toString()); } mContext.startActivity(launch); }); break; } } void setActivities(Node hierarchy) { // Build list of TaskStackBuilders from task hierarchy modeled by Node if (hierarchy.mChildren.isEmpty()) return; mBuilders.clear(); hierarchy.mChildren.forEach(taskParent -> { TaskStackBuilder tb = TaskStackBuilder.create(mContext); Intent taskRoot = new Intent() .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK) .setComponent(taskParent.mChildren.get(0).mName); tb.addNextIntent(taskRoot); taskParent.mChildren.subList(1, taskParent.mChildren.size()).forEach(activity -> tb.addNextIntent(new Intent().setComponent(activity.mName))); mBuilders.add(tb); }); // Edit the mIntent of the last activity in the last task so that it will relaunch the // activity that constructed this TestBase TaskStackBuilder tsb = mBuilders.get(mBuilders.size() - 1); Intent lastIntent = tsb.editIntentAt(tsb.getIntentCount() - 1); Intent launcherIntent = new Intent(mContext, mContext.getClass()); lastIntent.putParcelableArrayListExtra(BaseActivity.EXTRA_LAUNCH_FORWARD, new ArrayList<>(singletonList(launcherIntent))); } public Context getContext() { return mContext; } /** * An enum representing options for launching a series of tasks using this TestBase. */ enum LaunchStyle { TASK_STACK_BUILDER, COMMAND_LINE, LAUNCH_FORWARD} }