1 /* 2 * Copyright (C) 2021 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 android.window; 18 19 import android.annotation.CallSuper; 20 import android.annotation.NonNull; 21 import android.annotation.TestApi; 22 import android.content.res.Configuration; 23 import android.os.Bundle; 24 import android.os.IBinder; 25 import android.os.RemoteException; 26 import android.view.RemoteAnimationDefinition; 27 28 import java.util.concurrent.Executor; 29 30 /** 31 * Interface for WindowManager to delegate control of {@code TaskFragment}. 32 * @hide 33 */ 34 @TestApi 35 public class TaskFragmentOrganizer extends WindowOrganizer { 36 37 /** 38 * Key to the exception in {@link Bundle} in {@link ITaskFragmentOrganizer#onTaskFragmentError}. 39 */ 40 private static final String KEY_ERROR_CALLBACK_EXCEPTION = "fragment_exception"; 41 42 /** 43 * Creates a {@link Bundle} with an exception that can be passed to 44 * {@link ITaskFragmentOrganizer#onTaskFragmentError}. 45 * @hide 46 */ putExceptionInBundle(@onNull Throwable exception)47 public static Bundle putExceptionInBundle(@NonNull Throwable exception) { 48 final Bundle exceptionBundle = new Bundle(); 49 exceptionBundle.putSerializable(KEY_ERROR_CALLBACK_EXCEPTION, exception); 50 return exceptionBundle; 51 } 52 53 /** 54 * Callbacks from WM Core are posted on this executor. 55 */ 56 private final Executor mExecutor; 57 TaskFragmentOrganizer(@onNull Executor executor)58 public TaskFragmentOrganizer(@NonNull Executor executor) { 59 mExecutor = executor; 60 } 61 62 /** 63 * Gets the executor to run callbacks on. 64 */ 65 @NonNull getExecutor()66 public Executor getExecutor() { 67 return mExecutor; 68 } 69 70 /** 71 * Registers a TaskFragmentOrganizer to manage TaskFragments. 72 */ 73 @CallSuper registerOrganizer()74 public void registerOrganizer() { 75 try { 76 getController().registerOrganizer(mInterface); 77 } catch (RemoteException e) { 78 throw e.rethrowFromSystemServer(); 79 } 80 } 81 82 /** 83 * Unregisters a previously registered TaskFragmentOrganizer. 84 */ 85 @CallSuper unregisterOrganizer()86 public void unregisterOrganizer() { 87 try { 88 getController().unregisterOrganizer(mInterface); 89 } catch (RemoteException e) { 90 throw e.rethrowFromSystemServer(); 91 } 92 } 93 94 /** 95 * Registers remote animations per transition type for the organizer. It will override the 96 * animations if the transition only contains windows that belong to the organized 97 * TaskFragments. 98 * @hide 99 */ 100 @CallSuper registerRemoteAnimations(@onNull RemoteAnimationDefinition definition)101 public void registerRemoteAnimations(@NonNull RemoteAnimationDefinition definition) { 102 try { 103 getController().registerRemoteAnimations(mInterface, definition); 104 } catch (RemoteException e) { 105 throw e.rethrowFromSystemServer(); 106 } 107 } 108 109 /** 110 * Unregisters remote animations per transition type for the organizer. 111 * @hide 112 */ 113 @CallSuper unregisterRemoteAnimations()114 public void unregisterRemoteAnimations() { 115 try { 116 getController().unregisterRemoteAnimations(mInterface); 117 } catch (RemoteException e) { 118 throw e.rethrowFromSystemServer(); 119 } 120 } 121 122 /** Called when a TaskFragment is created and organized by this organizer. */ onTaskFragmentAppeared(@onNull TaskFragmentInfo taskFragmentInfo)123 public void onTaskFragmentAppeared(@NonNull TaskFragmentInfo taskFragmentInfo) {} 124 125 /** Called when the status of an organized TaskFragment is changed. */ onTaskFragmentInfoChanged(@onNull TaskFragmentInfo taskFragmentInfo)126 public void onTaskFragmentInfoChanged(@NonNull TaskFragmentInfo taskFragmentInfo) {} 127 128 /** Called when an organized TaskFragment is removed. */ onTaskFragmentVanished(@onNull TaskFragmentInfo taskFragmentInfo)129 public void onTaskFragmentVanished(@NonNull TaskFragmentInfo taskFragmentInfo) {} 130 131 /** 132 * Called when the parent leaf Task of organized TaskFragments is changed. 133 * When the leaf Task is changed, the organizer may want to update the TaskFragments in one 134 * transaction. 135 * 136 * For case like screen size change, it will trigger onTaskFragmentParentInfoChanged with new 137 * Task bounds, but may not trigger onTaskFragmentInfoChanged because there can be an override 138 * bounds. 139 */ onTaskFragmentParentInfoChanged( @onNull IBinder fragmentToken, @NonNull Configuration parentConfig)140 public void onTaskFragmentParentInfoChanged( 141 @NonNull IBinder fragmentToken, @NonNull Configuration parentConfig) {} 142 143 /** 144 * Called when the {@link WindowContainerTransaction} created with 145 * {@link WindowContainerTransaction#setErrorCallbackToken(IBinder)} failed on the server side. 146 * 147 * @param errorCallbackToken token set in 148 * {@link WindowContainerTransaction#setErrorCallbackToken(IBinder)} 149 * @param exception exception from the server side. 150 */ onTaskFragmentError( @onNull IBinder errorCallbackToken, @NonNull Throwable exception)151 public void onTaskFragmentError( 152 @NonNull IBinder errorCallbackToken, @NonNull Throwable exception) {} 153 154 @Override applyTransaction(@onNull WindowContainerTransaction t)155 public void applyTransaction(@NonNull WindowContainerTransaction t) { 156 t.setTaskFragmentOrganizer(mInterface); 157 super.applyTransaction(t); 158 } 159 160 // Suppress the lint because it is not a registration method. 161 @SuppressWarnings("ExecutorRegistration") 162 @Override applySyncTransaction(@onNull WindowContainerTransaction t, @NonNull WindowContainerTransactionCallback callback)163 public int applySyncTransaction(@NonNull WindowContainerTransaction t, 164 @NonNull WindowContainerTransactionCallback callback) { 165 t.setTaskFragmentOrganizer(mInterface); 166 return super.applySyncTransaction(t, callback); 167 } 168 169 private final ITaskFragmentOrganizer mInterface = new ITaskFragmentOrganizer.Stub() { 170 @Override 171 public void onTaskFragmentAppeared(@NonNull TaskFragmentInfo taskFragmentInfo) { 172 mExecutor.execute( 173 () -> TaskFragmentOrganizer.this.onTaskFragmentAppeared(taskFragmentInfo)); 174 } 175 176 @Override 177 public void onTaskFragmentInfoChanged(@NonNull TaskFragmentInfo taskFragmentInfo) { 178 mExecutor.execute( 179 () -> TaskFragmentOrganizer.this.onTaskFragmentInfoChanged(taskFragmentInfo)); 180 } 181 182 @Override 183 public void onTaskFragmentVanished(@NonNull TaskFragmentInfo taskFragmentInfo) { 184 mExecutor.execute( 185 () -> TaskFragmentOrganizer.this.onTaskFragmentVanished(taskFragmentInfo)); 186 } 187 188 @Override 189 public void onTaskFragmentParentInfoChanged( 190 @NonNull IBinder fragmentToken, @NonNull Configuration parentConfig) { 191 mExecutor.execute( 192 () -> TaskFragmentOrganizer.this.onTaskFragmentParentInfoChanged( 193 fragmentToken, parentConfig)); 194 } 195 196 @Override 197 public void onTaskFragmentError( 198 @NonNull IBinder errorCallbackToken, @NonNull Bundle exceptionBundle) { 199 mExecutor.execute(() -> TaskFragmentOrganizer.this.onTaskFragmentError( 200 errorCallbackToken, 201 (Throwable) exceptionBundle.getSerializable(KEY_ERROR_CALLBACK_EXCEPTION))); 202 } 203 }; 204 205 private final TaskFragmentOrganizerToken mToken = new TaskFragmentOrganizerToken(mInterface); 206 207 @NonNull getOrganizerToken()208 public TaskFragmentOrganizerToken getOrganizerToken() { 209 return mToken; 210 } 211 getController()212 private ITaskFragmentOrganizerController getController() { 213 try { 214 return getWindowOrganizerController().getTaskFragmentOrganizerController(); 215 } catch (RemoteException e) { 216 return null; 217 } 218 } 219 220 /** 221 * Checks if an activity organized by a {@link android.window.TaskFragmentOrganizer} and 222 * only occupies a portion of Task bounds. 223 * @hide 224 */ isActivityEmbedded(@onNull IBinder activityToken)225 public boolean isActivityEmbedded(@NonNull IBinder activityToken) { 226 try { 227 return getController().isActivityEmbedded(activityToken); 228 } catch (RemoteException e) { 229 throw e.rethrowFromSystemServer(); 230 } 231 } 232 } 233