1 /* 2 * Copyright (C) 2020 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.test.taskembed; 18 19 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES; 20 21 import android.app.Activity; 22 import android.app.ActivityManager; 23 import android.content.Context; 24 import android.content.Intent; 25 import android.graphics.Canvas; 26 import android.graphics.Color; 27 import android.graphics.Rect; 28 import android.os.Bundle; 29 import android.view.Gravity; 30 import android.view.SurfaceControl; 31 import android.widget.FrameLayout; 32 import android.widget.TextView; 33 import android.window.TaskOrganizer; 34 import android.window.WindowContainerTransactionCallback; 35 36 import java.util.concurrent.CountDownLatch; 37 38 public class TaskOrganizerMultiWindowTest extends Activity { 39 private CountDownLatch mTasksReadyLatch; 40 private CountDownLatch mTasksResizeLatch; 41 42 class Organizer extends TaskOrganizer { 43 private int mReceivedTransactions = 0; 44 private SurfaceControl.Transaction mMergedTransaction = new SurfaceControl.Transaction(); 45 WindowContainerTransactionCallback mTransactionCallback = 46 new WindowContainerTransactionCallback() { 47 @Override 48 public void onTransactionReady(int id, SurfaceControl.Transaction t) { 49 mMergedTransaction.merge(t); 50 mReceivedTransactions++; 51 if (mReceivedTransactions == 2) { 52 mReceivedTransactions = 0; 53 mMergedTransaction.apply(true); 54 if (mTasksResizeLatch != null) { 55 mTasksResizeLatch.countDown(); 56 } 57 } 58 } 59 }; 60 61 @Override onTaskAppeared(ActivityManager.RunningTaskInfo ti, SurfaceControl leash)62 public void onTaskAppeared(ActivityManager.RunningTaskInfo ti, SurfaceControl leash) { 63 if (ti.baseActivity == null) { 64 return; 65 } 66 67 final String clsName = ti.baseActivity.getClassName(); 68 if (clsName.contentEquals(TestActivity1.class.getName())) { 69 mTaskView1.reparentTask(ti.token, leash); 70 mOrganizer.setInterceptBackPressedOnTaskRoot(ti.token, true); 71 mTasksReadyLatch.countDown(); 72 } else if (clsName.contentEquals(TestActivity2.class.getName())) { 73 mTaskView2.reparentTask(ti.token, leash); 74 mOrganizer.setInterceptBackPressedOnTaskRoot(ti.token, true); 75 mTasksReadyLatch.countDown(); 76 } 77 } 78 79 @Override onBackPressedOnTaskRoot(ActivityManager.RunningTaskInfo taskInfo)80 public void onBackPressedOnTaskRoot(ActivityManager.RunningTaskInfo taskInfo) { 81 getMainThreadHandler().post(() -> { 82 finish(); 83 }); 84 } 85 } 86 87 private Organizer mOrganizer = new Organizer(); 88 private FrameLayout mTasksLayout; 89 private TaskView mTaskView1; 90 private TaskView mTaskView2; 91 @Override onCreate(Bundle savedInstanceState)92 protected void onCreate(Bundle savedInstanceState) { 93 super.onCreate(savedInstanceState); 94 getWindow().getAttributes().layoutInDisplayCutoutMode = 95 LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES; 96 97 mTasksLayout = new FrameLayout(this); 98 setContentView(mTasksLayout); 99 100 mOrganizer.registerOrganizer(); 101 } 102 103 @Override onDestroy()104 protected void onDestroy() { 105 super.onDestroy(); 106 mOrganizer.unregisterOrganizer(); 107 mTasksLayout.removeAllViews(); 108 } 109 makeActivityIntent(final Class<?> clazz)110 private Intent makeActivityIntent(final Class<?> clazz) { 111 Intent intent = new Intent(this, clazz); 112 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_NO_ANIMATION 113 | Intent.FLAG_ACTIVITY_CLEAR_TASK); 114 return intent; 115 } 116 openTaskView(Rect firstBounds, Rect secondBounds)117 public CountDownLatch openTaskView(Rect firstBounds, Rect secondBounds) { 118 mTasksReadyLatch = new CountDownLatch(2); 119 mTaskView1 = new TaskView(this, mOrganizer, makeActivityIntent(TestActivity1.class)); 120 mTaskView1.setBackgroundColor(Color.DKGRAY); 121 122 FrameLayout.LayoutParams viewLayout1 = 123 new FrameLayout.LayoutParams(firstBounds.width(), firstBounds.height(), 124 Gravity.TOP | Gravity.LEFT); 125 viewLayout1.setMargins(firstBounds.left, firstBounds.top, 0, 0); 126 mTasksLayout.addView(mTaskView1, viewLayout1); 127 128 mTaskView2 = new TaskView(this, mOrganizer, makeActivityIntent(TestActivity2.class)); 129 mTaskView2.setBackgroundColor(Color.LTGRAY); 130 FrameLayout.LayoutParams viewLayout2 = 131 new FrameLayout.LayoutParams(secondBounds.width(), secondBounds.height(), 132 Gravity.TOP | Gravity.LEFT); 133 viewLayout2.setMargins(secondBounds.left, secondBounds.top, 0, 0); 134 mTasksLayout.addView(mTaskView2, viewLayout2); 135 return mTasksReadyLatch; 136 } 137 resizeTaskView(Rect firstBounds, Rect secondBounds)138 public CountDownLatch resizeTaskView(Rect firstBounds, Rect secondBounds) { 139 mTasksResizeLatch = new CountDownLatch(1); 140 141 mTaskView1.resizeTask(firstBounds.width(), firstBounds.height()); 142 mTaskView2.resizeTask(secondBounds.width(), secondBounds.height()); 143 144 return mTasksResizeLatch; 145 } 146 147 static class InstrumentedTextView extends TextView { 148 private final boolean mSlowDraw; InstrumentedTextView(Context context, boolean slowDraw)149 InstrumentedTextView(Context context, boolean slowDraw) { 150 super(context); 151 mSlowDraw = slowDraw; 152 } 153 154 @Override onDraw(Canvas canvas)155 protected void onDraw(Canvas canvas) { 156 super.onDraw(canvas); 157 if (mSlowDraw) { 158 try { 159 Thread.sleep(20); 160 } catch (InterruptedException e) { 161 e.printStackTrace(); 162 } 163 } 164 } 165 } 166 167 public static class TestActivity1 extends Activity { 168 @Override onCreate(Bundle savedInstanceState)169 protected void onCreate(Bundle savedInstanceState) { 170 super.onCreate(savedInstanceState); 171 getWindow().getAttributes().layoutInDisplayCutoutMode = 172 LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES; 173 174 TextView v = new InstrumentedTextView(this, true); 175 v.setText("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz" 176 + "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"); 177 v.setBackgroundColor(Color.RED); 178 v.setTextColor(Color.BLACK); 179 setContentView(v); 180 } 181 } 182 183 public static class TestActivity2 extends Activity { 184 @Override onCreate(Bundle savedInstanceState)185 protected void onCreate(Bundle savedInstanceState) { 186 super.onCreate(savedInstanceState); 187 getWindow().getAttributes().layoutInDisplayCutoutMode = 188 LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES; 189 TextView v = new InstrumentedTextView(this, false); 190 v.setText("ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ" 191 + "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ"); 192 v.setBackgroundColor(Color.GREEN); 193 v.setTextColor(Color.BLACK); 194 setContentView(v); 195 } 196 } 197 } 198