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.systemui.bubbles; 18 19 import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_BUBBLES; 20 import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME; 21 22 import android.annotation.NonNull; 23 import android.annotation.Nullable; 24 import android.app.ActivityOptions; 25 import android.app.PendingIntent; 26 import android.window.TaskEmbedder; 27 import android.window.TaskOrganizerTaskEmbedder; 28 import android.content.Context; 29 import android.content.Intent; 30 import android.content.pm.ShortcutInfo; 31 import android.graphics.Matrix; 32 import android.graphics.Point; 33 import android.graphics.Rect; 34 import android.graphics.Region; 35 import android.view.IWindow; 36 import android.view.SurfaceControl; 37 import android.view.SurfaceHolder; 38 import android.view.SurfaceView; 39 40 import dalvik.system.CloseGuard; 41 42 43 public class BubbleTaskView extends SurfaceView implements SurfaceHolder.Callback, 44 TaskEmbedder.Host { 45 private static final String TAG = TAG_WITH_CLASS_NAME ? "BubbleTaskView" : TAG_BUBBLES; 46 47 private final CloseGuard mGuard = CloseGuard.get(); 48 private boolean mOpened; // Protected by mGuard. 49 50 private TaskEmbedder mTaskEmbedder; 51 private final SurfaceControl.Transaction mTmpTransaction = new SurfaceControl.Transaction(); 52 private final Rect mTmpRect = new Rect(); 53 BubbleTaskView(Context context)54 public BubbleTaskView(Context context) { 55 super(context); 56 57 mTaskEmbedder = new TaskOrganizerTaskEmbedder(context, this); 58 setUseAlpha(); 59 getHolder().addCallback(this); 60 61 mOpened = true; 62 mGuard.open("release"); 63 } 64 setCallback(TaskEmbedder.Listener callback)65 public void setCallback(TaskEmbedder.Listener callback) { 66 if (callback == null) { 67 mTaskEmbedder.setListener(null); 68 return; 69 } 70 mTaskEmbedder.setListener(callback); 71 } 72 startShortcutActivity(@onNull ShortcutInfo shortcut, @NonNull ActivityOptions options, @Nullable Rect sourceBounds)73 public void startShortcutActivity(@NonNull ShortcutInfo shortcut, 74 @NonNull ActivityOptions options, @Nullable Rect sourceBounds) { 75 mTaskEmbedder.startShortcutActivity(shortcut, options, sourceBounds); 76 } 77 startActivity(@onNull PendingIntent pendingIntent, @Nullable Intent fillInIntent, @NonNull ActivityOptions options)78 public void startActivity(@NonNull PendingIntent pendingIntent, @Nullable Intent fillInIntent, 79 @NonNull ActivityOptions options) { 80 mTaskEmbedder.startActivity(pendingIntent, fillInIntent, options); 81 } 82 onLocationChanged()83 public void onLocationChanged() { 84 mTaskEmbedder.notifyBoundsChanged(); 85 } 86 87 @Override getScreenBounds()88 public Rect getScreenBounds() { 89 getBoundsOnScreen(mTmpRect); 90 return mTmpRect; 91 } 92 93 @Override onTaskBackgroundColorChanged(TaskEmbedder ts, int bgColor)94 public void onTaskBackgroundColorChanged(TaskEmbedder ts, int bgColor) { 95 setResizeBackgroundColor(bgColor); 96 } 97 98 @Override getTapExcludeRegion()99 public Region getTapExcludeRegion() { 100 // Not used 101 return null; 102 } 103 104 @Override getScreenToTaskMatrix()105 public Matrix getScreenToTaskMatrix() { 106 // Not used 107 return null; 108 } 109 110 @Override getWindow()111 public IWindow getWindow() { 112 // Not used 113 return null; 114 } 115 116 @Override getPositionInWindow()117 public Point getPositionInWindow() { 118 // Not used 119 return null; 120 } 121 122 @Override canReceivePointerEvents()123 public boolean canReceivePointerEvents() { 124 // Not used 125 return false; 126 } 127 release()128 public void release() { 129 if (!mTaskEmbedder.isInitialized()) { 130 throw new IllegalStateException( 131 "Trying to release container that is not initialized."); 132 } 133 performRelease(); 134 } 135 136 @Override finalize()137 protected void finalize() throws Throwable { 138 try { 139 if (mGuard != null) { 140 mGuard.warnIfOpen(); 141 performRelease(); 142 } 143 } finally { 144 super.finalize(); 145 } 146 } 147 performRelease()148 private void performRelease() { 149 if (!mOpened) { 150 return; 151 } 152 getHolder().removeCallback(this); 153 mTaskEmbedder.release(); 154 mTaskEmbedder.setListener(null); 155 156 mGuard.close(); 157 mOpened = false; 158 } 159 160 @Override surfaceCreated(SurfaceHolder holder)161 public void surfaceCreated(SurfaceHolder holder) { 162 if (!mTaskEmbedder.isInitialized()) { 163 mTaskEmbedder.initialize(getSurfaceControl()); 164 } else { 165 mTmpTransaction.reparent(mTaskEmbedder.getSurfaceControl(), 166 getSurfaceControl()).apply(); 167 } 168 mTaskEmbedder.start(); 169 } 170 171 @Override surfaceChanged(SurfaceHolder holder, int format, int width, int height)172 public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { 173 mTaskEmbedder.resizeTask(width, height); 174 mTaskEmbedder.notifyBoundsChanged(); 175 } 176 177 @Override surfaceDestroyed(SurfaceHolder holder)178 public void surfaceDestroyed(SurfaceHolder holder) { 179 mTaskEmbedder.stop(); 180 } 181 } 182