Home | History | Annotate | Download | only in impl
      1 /*
      2  * Copyright (C) 2008 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.internal.policy.impl;
     18 
     19 import android.app.ActivityManager;
     20 import android.app.Dialog;
     21 import android.app.StatusBarManager;
     22 import android.content.BroadcastReceiver;
     23 import android.content.ComponentName;
     24 import android.content.Context;
     25 import android.content.Intent;
     26 import android.content.IntentFilter;
     27 import android.content.res.Resources;
     28 import android.content.pm.ActivityInfo;
     29 import android.content.pm.PackageManager;
     30 import android.content.pm.ResolveInfo;
     31 import android.graphics.drawable.Drawable;
     32 import android.os.Bundle;
     33 import android.os.Handler;
     34 import android.os.Message;
     35 import android.view.View;
     36 import android.view.Window;
     37 import android.view.WindowManager;
     38 import android.view.View.OnClickListener;
     39 import android.widget.ImageView;
     40 import android.widget.TextView;
     41 
     42 import java.util.List;
     43 
     44 public class RecentApplicationsDialog extends Dialog implements OnClickListener {
     45     // Elements for debugging support
     46 //  private static final String LOG_TAG = "RecentApplicationsDialog";
     47     private static final boolean DBG_FORCE_EMPTY_LIST = false;
     48 
     49     static private StatusBarManager sStatusBar;
     50 
     51     private static final int NUM_BUTTONS = 6;
     52     private static final int MAX_RECENT_TASKS = NUM_BUTTONS * 2;    // allow for some discards
     53 
     54     final View[] mButtons = new View[NUM_BUTTONS];
     55     View mNoAppsText;
     56     IntentFilter mBroadcastIntentFilter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
     57 
     58     private int mIconSize;
     59 
     60     public RecentApplicationsDialog(Context context) {
     61         super(context);
     62 
     63         final Resources resources = context.getResources();
     64         mIconSize = (int) resources.getDimension(android.R.dimen.app_icon_size);
     65     }
     66 
     67     /**
     68      * We create the recent applications dialog just once, and it stays around (hidden)
     69      * until activated by the user.
     70      *
     71      * @see MidWindowManager#showRecentAppsDialog
     72      */
     73     @Override
     74     protected void onCreate(Bundle savedInstanceState) {
     75         super.onCreate(savedInstanceState);
     76 
     77         Context context = getContext();
     78 
     79         if (sStatusBar == null) {
     80             sStatusBar = (StatusBarManager)context.getSystemService(Context.STATUS_BAR_SERVICE);
     81         }
     82 
     83         Window theWindow = getWindow();
     84         theWindow.requestFeature(Window.FEATURE_NO_TITLE);
     85         theWindow.setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
     86         theWindow.setFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND,
     87                            WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
     88         theWindow.setTitle("Recents");
     89 
     90         setContentView(com.android.internal.R.layout.recent_apps_dialog);
     91 
     92         mButtons[0] = findViewById(com.android.internal.R.id.button1);
     93         mButtons[1] = findViewById(com.android.internal.R.id.button2);
     94         mButtons[2] = findViewById(com.android.internal.R.id.button3);
     95         mButtons[3] = findViewById(com.android.internal.R.id.button4);
     96         mButtons[4] = findViewById(com.android.internal.R.id.button5);
     97         mButtons[5] = findViewById(com.android.internal.R.id.button6);
     98         mNoAppsText = findViewById(com.android.internal.R.id.no_applications_message);
     99 
    100         for (View b : mButtons) {
    101             b.setOnClickListener(this);
    102         }
    103     }
    104 
    105     /**
    106      * Handler for user clicks.  If a button was clicked, launch the corresponding activity.
    107      */
    108     public void onClick(View v) {
    109 
    110         for (View b : mButtons) {
    111             if (b == v) {
    112                 // prepare a launch intent and send it
    113                 Intent intent = (Intent)b.getTag();
    114                 getContext().startActivity(intent);
    115             }
    116         }
    117         dismiss();
    118     }
    119 
    120     /**
    121      * Set up and show the recent activities dialog.
    122      */
    123     @Override
    124     public void onStart() {
    125         super.onStart();
    126         reloadButtons();
    127         if (sStatusBar != null) {
    128             sStatusBar.disable(StatusBarManager.DISABLE_EXPAND);
    129         }
    130 
    131         // receive broadcasts
    132         getContext().registerReceiver(mBroadcastReceiver, mBroadcastIntentFilter);
    133     }
    134 
    135     /**
    136      * Dismiss the recent activities dialog.
    137      */
    138     @Override
    139     public void onStop() {
    140         super.onStop();
    141 
    142         // dump extra memory we're hanging on to
    143         for (View b : mButtons) {
    144             setButtonAppearance(b, null, null);
    145             b.setTag(null);
    146         }
    147 
    148         if (sStatusBar != null) {
    149             sStatusBar.disable(StatusBarManager.DISABLE_NONE);
    150         }
    151 
    152         // stop receiving broadcasts
    153         getContext().unregisterReceiver(mBroadcastReceiver);
    154      }
    155 
    156     /**
    157      * Reload the 6 buttons with recent activities
    158      */
    159     private void reloadButtons() {
    160 
    161         final Context context = getContext();
    162         final PackageManager pm = context.getPackageManager();
    163         final ActivityManager am = (ActivityManager)
    164                                         context.getSystemService(Context.ACTIVITY_SERVICE);
    165         final List<ActivityManager.RecentTaskInfo> recentTasks =
    166                                         am.getRecentTasks(MAX_RECENT_TASKS, 0);
    167 
    168         ResolveInfo homeInfo = pm.resolveActivity(
    169                 new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME),
    170                 0);
    171 
    172         // Performance note:  Our android performance guide says to prefer Iterator when
    173         // using a List class, but because we know that getRecentTasks() always returns
    174         // an ArrayList<>, we'll use a simple index instead.
    175         int button = 0;
    176         int numTasks = recentTasks.size();
    177         for (int i = 0; i < numTasks && (button < NUM_BUTTONS); ++i) {
    178             final ActivityManager.RecentTaskInfo info = recentTasks.get(i);
    179 
    180             // for debug purposes only, disallow first result to create empty lists
    181             if (DBG_FORCE_EMPTY_LIST && (i == 0)) continue;
    182 
    183             Intent intent = new Intent(info.baseIntent);
    184             if (info.origActivity != null) {
    185                 intent.setComponent(info.origActivity);
    186             }
    187 
    188             // Skip the current home activity.
    189             if (homeInfo != null) {
    190                 if (homeInfo.activityInfo.packageName.equals(
    191                         intent.getComponent().getPackageName())
    192                         && homeInfo.activityInfo.name.equals(
    193                                 intent.getComponent().getClassName())) {
    194                     continue;
    195                 }
    196             }
    197 
    198             intent.setFlags((intent.getFlags()&~Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED)
    199                     | Intent.FLAG_ACTIVITY_NEW_TASK);
    200             final ResolveInfo resolveInfo = pm.resolveActivity(intent, 0);
    201             if (resolveInfo != null) {
    202                 final ActivityInfo activityInfo = resolveInfo.activityInfo;
    203                 final String title = activityInfo.loadLabel(pm).toString();
    204                 final Drawable icon = activityInfo.loadIcon(pm);
    205 
    206                 if (title != null && title.length() > 0 && icon != null) {
    207                     final View b = mButtons[button];
    208                     setButtonAppearance(b, title, icon);
    209                     b.setTag(intent);
    210                     b.setVisibility(View.VISIBLE);
    211                     b.setPressed(false);
    212                     b.clearFocus();
    213                     ++button;
    214                 }
    215             }
    216         }
    217 
    218         // handle the case of "no icons to show"
    219         mNoAppsText.setVisibility((button == 0) ? View.VISIBLE : View.GONE);
    220 
    221         // hide the rest
    222         for ( ; button < NUM_BUTTONS; ++button) {
    223             mButtons[button].setVisibility(View.GONE);
    224         }
    225     }
    226 
    227     /**
    228      * Adjust appearance of each icon-button
    229      */
    230     private void setButtonAppearance(View theButton, final String theTitle, final Drawable icon) {
    231         TextView tv = (TextView) theButton;
    232         tv.setText(theTitle);
    233         if (icon != null) {
    234             icon.setBounds(0, 0, mIconSize, mIconSize);
    235         }
    236         tv.setCompoundDrawables(null, icon, null, null);
    237     }
    238 
    239     /**
    240      * This is the listener for the ACTION_CLOSE_SYSTEM_DIALOGS intent.  It's an indication that
    241      * we should close ourselves immediately, in order to allow a higher-priority UI to take over
    242      * (e.g. phone call received).
    243      */
    244     private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
    245         @Override
    246         public void onReceive(Context context, Intent intent) {
    247             String action = intent.getAction();
    248             if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {
    249                 String reason = intent.getStringExtra(MidWindowManager.SYSTEM_DIALOG_REASON_KEY);
    250                 if (! MidWindowManager.SYSTEM_DIALOG_REASON_RECENT_APPS.equals(reason)) {
    251                     dismiss();
    252                 }
    253             }
    254         }
    255     };
    256 }
    257