[go: nahoru, domu]

1/*
2 * Copyright (C) 2016 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 */
16package com.android.systemui.recents.tv.views;
17
18import android.annotation.Nullable;
19import android.app.ActivityOptions;
20import android.content.Context;
21import android.graphics.Bitmap;
22import android.graphics.Rect;
23import android.os.Bundle;
24import android.os.Handler;
25import android.os.IRemoteCallback;
26import android.os.RemoteException;
27import android.util.Log;
28import android.view.WindowManagerGlobal;
29import com.android.internal.annotations.GuardedBy;
30import com.android.systemui.recents.Recents;
31import com.android.systemui.recents.events.EventBus;
32import com.android.systemui.recents.events.activity.*;
33import com.android.systemui.recents.misc.SystemServicesProxy;
34import com.android.systemui.recents.model.Task;
35import com.android.systemui.recents.model.TaskStack;
36
37
38public class RecentsTvTransitionHelper {
39    private static final String TAG = "RecentsTvTransitionHelper";
40
41    private Context mContext;
42    private Handler mHandler;
43
44    public RecentsTvTransitionHelper(Context context, Handler handler) {
45        mContext = context;
46        mHandler = handler;
47    }
48
49    public void launchTaskFromRecents(final TaskStack stack, @Nullable final Task task,
50            final TaskStackHorizontalGridView stackView, final TaskCardView taskView,
51            final Rect bounds, int destinationStack) {
52        final ActivityOptions opts = ActivityOptions.makeBasic();
53        if (bounds != null) {
54            opts.setLaunchBounds(bounds.isEmpty() ? null : bounds);
55        }
56
57        final ActivityOptions.OnAnimationStartedListener animStartedListener;
58        if (task.thumbnail != null && task.thumbnail.getWidth() > 0 &&
59                task.thumbnail.getHeight() > 0) {
60            animStartedListener = new ActivityOptions.OnAnimationStartedListener() {
61                @Override
62                public void onAnimationStarted() {
63                    // If we are launching into another task, cancel the previous task's
64                    // window transition
65                    EventBus.getDefault().send(new CancelEnterRecentsWindowAnimationEvent(task));
66                    EventBus.getDefault().send(new ExitRecentsWindowFirstAnimationFrameEvent());
67                }
68            };
69        } else {
70            // This is only the case if the task is not on screen (scrolled offscreen for example)
71            animStartedListener = new ActivityOptions.OnAnimationStartedListener() {
72                @Override
73                public void onAnimationStarted() {
74                    EventBus.getDefault().send(new ExitRecentsWindowFirstAnimationFrameEvent());
75                }
76            };
77        }
78
79        if (taskView == null) {
80            // If there is no task view, then we do not need to worry about animating out occluding
81            // task views, and we can launch immediately
82            startTaskActivity(stack, task, taskView, opts, animStartedListener);
83        } else {
84            LaunchTvTaskStartedEvent launchStartedEvent = new LaunchTvTaskStartedEvent(taskView);
85            EventBus.getDefault().send(launchStartedEvent);
86            startTaskActivity(stack, task, taskView, opts, animStartedListener);
87        }
88    }
89
90    private void startTaskActivity(TaskStack stack, Task task, @Nullable TaskCardView taskView,
91            ActivityOptions opts,final ActivityOptions.OnAnimationStartedListener animStartedListener) {
92        SystemServicesProxy ssp = Recents.getSystemServices();
93        if (ssp.startActivityFromRecents(mContext, task.key, task.title, opts)) {
94            // Keep track of the index of the task launch
95            int taskIndexFromFront = 0;
96            int taskIndex = stack.indexOfStackTask(task);
97            if (taskIndex > -1) {
98                taskIndexFromFront = stack.getTaskCount() - taskIndex - 1;
99            }
100            EventBus.getDefault().send(new LaunchTaskSucceededEvent(taskIndexFromFront));
101        } else {
102            // Keep track of failed launches
103            EventBus.getDefault().send(new LaunchTaskFailedEvent());
104        }
105
106        Rect taskRect = taskView.getFocusedThumbnailRect();
107        // Check both the rect and the thumbnail for null. The rect can be null if the user
108        // decides to disallow animations, so automatic scrolling does not happen properly.
109
110        // The thumbnail can be null if the app was partially launched on TV. In this case
111        // we do not override the transition.
112        if (taskRect == null || task.thumbnail == null) {
113            return;
114        }
115
116        IRemoteCallback.Stub callback = null;
117        if (animStartedListener != null) {
118            callback = new IRemoteCallback.Stub() {
119                @Override
120                public void sendResult(Bundle data) throws RemoteException {
121                    mHandler.post(new Runnable() {
122                        @Override
123                        public void run() {
124                            if (animStartedListener != null) {
125                                animStartedListener.onAnimationStarted();
126                            }
127                        }
128                    });
129                }
130            };
131        }
132        try {
133            Bitmap thumbnail = Bitmap.createScaledBitmap(task.thumbnail, taskRect.width(),
134                    taskRect.height(), false);
135            WindowManagerGlobal.getWindowManagerService()
136                    .overridePendingAppTransitionAspectScaledThumb(thumbnail, taskRect.left,
137                            taskRect.top, taskRect.width(), taskRect.height(), callback, true);
138        } catch (RemoteException e) {
139            Log.w(TAG, "Failed to override transition: " + e);
140        }
141    }
142}
143