| /* |
| * Copyright (C) 2016 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.android.systemui.recents.tv.views; |
| |
| import android.annotation.Nullable; |
| import android.app.ActivityOptions; |
| import android.content.Context; |
| import android.graphics.Rect; |
| import android.os.Bundle; |
| import android.os.Handler; |
| import android.os.IRemoteCallback; |
| import android.os.RemoteException; |
| import android.util.Log; |
| import android.view.WindowManagerGlobal; |
| import com.android.internal.annotations.GuardedBy; |
| import com.android.systemui.recents.Recents; |
| import com.android.systemui.recents.events.EventBus; |
| import com.android.systemui.recents.events.activity.*; |
| import com.android.systemui.recents.misc.SystemServicesProxy; |
| import com.android.systemui.recents.model.Task; |
| import com.android.systemui.recents.model.TaskStack; |
| |
| |
| public class RecentsTvTransitionHelper { |
| private static final String TAG = "RecentsTvTransitionHelper"; |
| |
| private Context mContext; |
| private Handler mHandler; |
| |
| public RecentsTvTransitionHelper(Context context, Handler handler) { |
| mContext = context; |
| mHandler = handler; |
| } |
| |
| public void launchTaskFromRecents(final TaskStack stack, @Nullable final Task task, |
| final TaskStackHorizontalGridView stackView, final TaskCardView taskView, |
| final Rect bounds, int destinationStack) { |
| final ActivityOptions opts = ActivityOptions.makeBasic(); |
| if (bounds != null) { |
| opts.setLaunchBounds(bounds.isEmpty() ? null : bounds); |
| } |
| |
| final ActivityOptions.OnAnimationStartedListener animStartedListener; |
| if (task.thumbnail != null && task.thumbnail.getWidth() > 0 && |
| task.thumbnail.getHeight() > 0) { |
| animStartedListener = new ActivityOptions.OnAnimationStartedListener() { |
| @Override |
| public void onAnimationStarted() { |
| // If we are launching into another task, cancel the previous task's |
| // window transition |
| EventBus.getDefault().send(new CancelEnterRecentsWindowAnimationEvent(task)); |
| EventBus.getDefault().send(new ExitRecentsWindowFirstAnimationFrameEvent()); |
| } |
| }; |
| } else { |
| // This is only the case if the task is not on screen (scrolled offscreen for example) |
| animStartedListener = new ActivityOptions.OnAnimationStartedListener() { |
| @Override |
| public void onAnimationStarted() { |
| EventBus.getDefault().send(new ExitRecentsWindowFirstAnimationFrameEvent()); |
| } |
| }; |
| } |
| |
| if (taskView == null) { |
| // If there is no task view, then we do not need to worry about animating out occluding |
| // task views, and we can launch immediately |
| startTaskActivity(stack, task, taskView, opts, animStartedListener); |
| } else { |
| LaunchTvTaskStartedEvent launchStartedEvent = new LaunchTvTaskStartedEvent(taskView); |
| EventBus.getDefault().send(launchStartedEvent); |
| startTaskActivity(stack, task, taskView, opts, animStartedListener); |
| } |
| } |
| |
| private void startTaskActivity(TaskStack stack, Task task, @Nullable TaskCardView taskView, |
| ActivityOptions opts,final ActivityOptions.OnAnimationStartedListener animStartedListener) { |
| SystemServicesProxy ssp = Recents.getSystemServices(); |
| if (ssp.startActivityFromRecents(mContext, task.key.id, task.title, opts)) { |
| // Keep track of the index of the task launch |
| int taskIndexFromFront = 0; |
| int taskIndex = stack.indexOfStackTask(task); |
| if (taskIndex > -1) { |
| taskIndexFromFront = stack.getTaskCount() - taskIndex - 1; |
| } |
| EventBus.getDefault().send(new LaunchTaskSucceededEvent(taskIndexFromFront)); |
| } else { |
| // Keep track of failed launches |
| EventBus.getDefault().send(new LaunchTaskFailedEvent()); |
| } |
| |
| IRemoteCallback.Stub callback = null; |
| if (animStartedListener != null) { |
| callback = new IRemoteCallback.Stub() { |
| @Override |
| public void sendResult(Bundle data) throws RemoteException { |
| mHandler.post(new Runnable() { |
| @Override |
| public void run() { |
| if (animStartedListener != null) { |
| animStartedListener.onAnimationStarted(); |
| } |
| } |
| }); |
| } |
| }; |
| } |
| try { |
| Rect taskRect = taskView.getFocusedThumbnailRect(); |
| WindowManagerGlobal.getWindowManagerService() |
| .overridePendingAppTransitionAspectScaledThumb(task.thumbnail, taskRect.left, |
| taskRect.top, taskRect.width(), taskRect.height(), callback, true); |
| } catch (RemoteException e) { |
| Log.w(TAG, "Failed to override transition: " + e); |
| } |
| } |
| } |