Recents.java revision cdcd487abad10f728f0542accc42a31d1f7fedac
1/*
2 * Copyright (C) 2013 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
17package com.android.systemui.recent;
18
19import android.app.ActivityOptions;
20import android.content.ActivityNotFoundException;
21import android.content.Intent;
22import android.content.res.Configuration;
23import android.content.res.Resources;
24import android.graphics.Bitmap;
25import android.graphics.Canvas;
26import android.graphics.Paint;
27import android.graphics.drawable.BitmapDrawable;
28import android.graphics.drawable.Drawable;
29import android.os.Bundle;
30import android.os.UserHandle;
31import android.util.DisplayMetrics;
32import android.util.Log;
33import android.view.Display;
34import android.view.View;
35import com.android.systemui.R;
36import com.android.systemui.RecentsComponent;
37import com.android.systemui.SystemUI;
38import com.android.systemui.recents.AlternateRecentsComponent;
39
40
41public class Recents extends SystemUI implements RecentsComponent {
42    private static final String TAG = "Recents";
43    private static final boolean DEBUG = true;
44
45    // Which recents to use
46    boolean mUseAlternateRecents = true;
47    AlternateRecentsComponent mAlternateRecents;
48    boolean mBootCompleted = false;
49
50    @Override
51    public void start() {
52        if (mUseAlternateRecents) {
53            if (mAlternateRecents == null) {
54                mAlternateRecents = new AlternateRecentsComponent(mContext);
55            }
56            mAlternateRecents.onStart();
57        }
58
59        putComponent(RecentsComponent.class, this);
60    }
61
62    @Override
63    protected void onBootCompleted() {
64        if (mUseAlternateRecents) {
65            if (mAlternateRecents != null) {
66                mAlternateRecents.onBootCompleted();
67            }
68        }
69        mBootCompleted = true;
70    }
71
72    @Override
73    public void showRecents(boolean triggeredFromAltTab, View statusBarView) {
74        if (mUseAlternateRecents) {
75            mAlternateRecents.onShowRecents(triggeredFromAltTab, statusBarView);
76        }
77    }
78
79    @Override
80    public void hideRecents(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) {
81        if (mUseAlternateRecents) {
82            mAlternateRecents.onHideRecents(triggeredFromAltTab, triggeredFromHomeKey);
83        } else {
84            Intent intent = new Intent(RecentsActivity.CLOSE_RECENTS_INTENT);
85            intent.setPackage("com.android.systemui");
86            sendBroadcastSafely(intent);
87
88            RecentTasksLoader.getInstance(mContext).cancelPreloadingFirstTask();
89        }
90    }
91
92    @Override
93    public void toggleRecents(Display display, int layoutDirection, View statusBarView) {
94        if (mUseAlternateRecents) {
95            // Launch the alternate recents if required
96            mAlternateRecents.onToggleRecents(statusBarView);
97            return;
98        }
99
100        if (DEBUG) Log.d(TAG, "toggle recents panel");
101        try {
102            TaskDescription firstTask = RecentTasksLoader.getInstance(mContext).getFirstTask();
103
104            Intent intent = new Intent(RecentsActivity.TOGGLE_RECENTS_INTENT);
105            intent.setClassName("com.android.systemui",
106                    "com.android.systemui.recent.RecentsActivity");
107            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
108                    | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
109
110            if (firstTask == null) {
111                if (RecentsActivity.forceOpaqueBackground(mContext)) {
112                    ActivityOptions opts = ActivityOptions.makeCustomAnimation(mContext,
113                            R.anim.recents_launch_from_launcher_enter,
114                            R.anim.recents_launch_from_launcher_exit);
115                    mContext.startActivityAsUser(intent, opts.toBundle(), new UserHandle(
116                            UserHandle.USER_CURRENT));
117                } else {
118                    // The correct window animation will be applied via the activity's style
119                    mContext.startActivityAsUser(intent, new UserHandle(
120                            UserHandle.USER_CURRENT));
121                }
122
123            } else {
124                Bitmap first = null;
125                if (firstTask.getThumbnail() instanceof BitmapDrawable) {
126                    first = ((BitmapDrawable) firstTask.getThumbnail()).getBitmap();
127                } else {
128                    first = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
129                    Drawable d = RecentTasksLoader.getInstance(mContext).getDefaultThumbnail();
130                    d.draw(new Canvas(first));
131                }
132                final Resources res = mContext.getResources();
133
134                float thumbWidth = res
135                        .getDimensionPixelSize(R.dimen.status_bar_recents_thumbnail_width);
136                float thumbHeight = res
137                        .getDimensionPixelSize(R.dimen.status_bar_recents_thumbnail_height);
138                if (first == null) {
139                    throw new RuntimeException("Recents thumbnail is null");
140                }
141                if (first.getWidth() != thumbWidth || first.getHeight() != thumbHeight) {
142                    first = Bitmap.createScaledBitmap(first, (int) thumbWidth, (int) thumbHeight,
143                            true);
144                    if (first == null) {
145                        throw new RuntimeException("Recents thumbnail is null");
146                    }
147                }
148
149
150                DisplayMetrics dm = new DisplayMetrics();
151                display.getMetrics(dm);
152                // calculate it here, but consider moving it elsewhere
153                // first, determine which orientation you're in.
154                final Configuration config = res.getConfiguration();
155                int x, y;
156
157                if (config.orientation == Configuration.ORIENTATION_PORTRAIT) {
158                    float appLabelLeftMargin = res.getDimensionPixelSize(
159                            R.dimen.status_bar_recents_app_label_left_margin);
160                    float appLabelWidth = res.getDimensionPixelSize(
161                            R.dimen.status_bar_recents_app_label_width);
162                    float thumbLeftMargin = res.getDimensionPixelSize(
163                            R.dimen.status_bar_recents_thumbnail_left_margin);
164                    float thumbBgPadding = res.getDimensionPixelSize(
165                            R.dimen.status_bar_recents_thumbnail_bg_padding);
166
167                    float width = appLabelLeftMargin +
168                            +appLabelWidth
169                            + thumbLeftMargin
170                            + thumbWidth
171                            + 2 * thumbBgPadding;
172
173                    x = (int) ((dm.widthPixels - width) / 2f + appLabelLeftMargin + appLabelWidth
174                            + thumbBgPadding + thumbLeftMargin);
175                    y = (int) (dm.heightPixels
176                            - res.getDimensionPixelSize(R.dimen.status_bar_recents_thumbnail_height)
177                            - thumbBgPadding);
178                    if (layoutDirection == View.LAYOUT_DIRECTION_RTL) {
179                        x = dm.widthPixels - x - res.getDimensionPixelSize(
180                                R.dimen.status_bar_recents_thumbnail_width);
181                    }
182
183                } else { // if (config.orientation == Configuration.ORIENTATION_LANDSCAPE) {
184                    float thumbTopMargin = res.getDimensionPixelSize(
185                            R.dimen.status_bar_recents_thumbnail_top_margin);
186                    float thumbBgPadding = res.getDimensionPixelSize(
187                            R.dimen.status_bar_recents_thumbnail_bg_padding);
188                    float textPadding = res.getDimensionPixelSize(
189                            R.dimen.status_bar_recents_text_description_padding);
190                    float labelTextSize = res.getDimensionPixelSize(
191                            R.dimen.status_bar_recents_app_label_text_size);
192                    Paint p = new Paint();
193                    p.setTextSize(labelTextSize);
194                    float labelTextHeight = p.getFontMetricsInt().bottom
195                            - p.getFontMetricsInt().top;
196                    float descriptionTextSize = res.getDimensionPixelSize(
197                            R.dimen.status_bar_recents_app_description_text_size);
198                    p.setTextSize(descriptionTextSize);
199                    float descriptionTextHeight = p.getFontMetricsInt().bottom
200                            - p.getFontMetricsInt().top;
201
202                    float statusBarHeight = res.getDimensionPixelSize(
203                            com.android.internal.R.dimen.status_bar_height);
204                    float recentsItemTopPadding = statusBarHeight;
205
206                    float height = thumbTopMargin
207                            + thumbHeight
208                            + 2 * thumbBgPadding + textPadding + labelTextHeight
209                            + recentsItemTopPadding + textPadding + descriptionTextHeight;
210                    float recentsItemRightPadding = res
211                            .getDimensionPixelSize(R.dimen.status_bar_recents_item_padding);
212                    float recentsScrollViewRightPadding = res
213                            .getDimensionPixelSize(R.dimen.status_bar_recents_right_glow_margin);
214                    x = (int) (dm.widthPixels - res
215                            .getDimensionPixelSize(R.dimen.status_bar_recents_thumbnail_width)
216                            - thumbBgPadding - recentsItemRightPadding
217                            - recentsScrollViewRightPadding);
218                    y = (int) ((dm.heightPixels - statusBarHeight - height) / 2f + thumbTopMargin
219                            + recentsItemTopPadding + thumbBgPadding + statusBarHeight);
220                }
221
222                ActivityOptions opts = ActivityOptions.makeThumbnailScaleDownAnimation(
223                        statusBarView,
224                        first, x, y,
225                        new ActivityOptions.OnAnimationStartedListener() {
226                            public void onAnimationStarted() {
227                                Intent intent =
228                                        new Intent(RecentsActivity.WINDOW_ANIMATION_START_INTENT);
229                                intent.setPackage("com.android.systemui");
230                                sendBroadcastSafely(intent);
231                            }
232                        });
233                intent.putExtra(RecentsActivity.WAITING_FOR_WINDOW_ANIMATION_PARAM, true);
234                startActivitySafely(intent, opts.toBundle());
235            }
236        } catch (ActivityNotFoundException e) {
237            Log.e(TAG, "Failed to launch RecentAppsIntent", e);
238        }
239    }
240
241    @Override
242    protected void onConfigurationChanged(Configuration newConfig) {
243        if (mUseAlternateRecents) {
244            mAlternateRecents.onConfigurationChanged(newConfig);
245        }
246    }
247
248    @Override
249    public void preloadRecents() {
250        if (mUseAlternateRecents) {
251            mAlternateRecents.onPreloadRecents();
252        } else {
253            Intent intent = new Intent(RecentsActivity.PRELOAD_INTENT);
254            intent.setClassName("com.android.systemui",
255                    "com.android.systemui.recent.RecentsPreloadReceiver");
256            sendBroadcastSafely(intent);
257
258            RecentTasksLoader.getInstance(mContext).preloadFirstTask();
259        }
260    }
261
262    @Override
263    public void cancelPreloadingRecents() {
264        if (mUseAlternateRecents) {
265            mAlternateRecents.onCancelPreloadingRecents();
266        } else {
267            Intent intent = new Intent(RecentsActivity.CANCEL_PRELOAD_INTENT);
268            intent.setClassName("com.android.systemui",
269                    "com.android.systemui.recent.RecentsPreloadReceiver");
270            sendBroadcastSafely(intent);
271
272            RecentTasksLoader.getInstance(mContext).cancelPreloadingFirstTask();
273        }
274    }
275
276    @Override
277    public void setCallback(Callbacks cb) {
278        if (mUseAlternateRecents) {
279            mAlternateRecents.setRecentsComponentCallback(cb);
280        }
281    }
282
283    /**
284     * Send broadcast only if BOOT_COMPLETED
285     */
286    private void sendBroadcastSafely(Intent intent) {
287        if (!mBootCompleted) return;
288        mContext.sendBroadcastAsUser(intent, new UserHandle(UserHandle.USER_CURRENT));
289    }
290
291    /**
292     * Start activity only if BOOT_COMPLETED
293     */
294    private void startActivitySafely(Intent intent, Bundle opts) {
295        if (!mBootCompleted) return;
296        mContext.startActivityAsUser(intent, opts, new UserHandle(UserHandle.USER_CURRENT));
297    }
298}
299