Home | History | Annotate | Download | only in settings
      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 
     17 package com.android.settings;
     18 
     19 import java.util.ArrayList;
     20 
     21 import android.app.ActivityManager;
     22 import android.content.ComponentName;
     23 import android.content.Context;
     24 import android.content.Intent;
     25 import android.content.IntentFilter;
     26 import android.content.SharedPreferences;
     27 import android.content.pm.ActivityInfo;
     28 import android.content.pm.ApplicationInfo;
     29 import android.content.pm.PackageInfo;
     30 import android.content.pm.PackageManager;
     31 import android.content.pm.ResolveInfo;
     32 import android.graphics.ColorFilter;
     33 import android.graphics.ColorMatrix;
     34 import android.graphics.ColorMatrixColorFilter;
     35 import android.graphics.drawable.Drawable;
     36 import android.net.Uri;
     37 import android.os.Bundle;
     38 import android.os.Handler;
     39 import android.preference.Preference;
     40 import android.preference.PreferenceGroup;
     41 import android.util.Log;
     42 import android.view.View;
     43 import android.view.View.OnClickListener;
     44 import android.widget.ImageView;
     45 import android.widget.RadioButton;
     46 
     47 public class HomeSettings extends SettingsPreferenceFragment {
     48     static final String TAG = "HomeSettings";
     49 
     50     static final int REQUESTING_UNINSTALL = 10;
     51 
     52     public static final String HOME_PREFS = "home_prefs";
     53     public static final String HOME_PREFS_DO_SHOW = "do_show";
     54 
     55     public static final String HOME_SHOW_NOTICE = "show";
     56 
     57     PreferenceGroup mPrefGroup;
     58 
     59     PackageManager mPm;
     60     ComponentName[] mHomeComponentSet;
     61     ArrayList<HomeAppPreference> mPrefs;
     62     HomeAppPreference mCurrentHome = null;
     63     final IntentFilter mHomeFilter;
     64     boolean mShowNotice;
     65 
     66     public HomeSettings() {
     67         mHomeFilter = new IntentFilter(Intent.ACTION_MAIN);
     68         mHomeFilter.addCategory(Intent.CATEGORY_HOME);
     69         mHomeFilter.addCategory(Intent.CATEGORY_DEFAULT);
     70     }
     71 
     72     OnClickListener mHomeClickListener = new OnClickListener() {
     73         @Override
     74         public void onClick(View v) {
     75             int index = (Integer)v.getTag();
     76             HomeAppPreference pref = mPrefs.get(index);
     77             if (!pref.isChecked) {
     78                 makeCurrentHome(pref);
     79             }
     80         }
     81     };
     82 
     83     OnClickListener mDeleteClickListener = new OnClickListener() {
     84         @Override
     85         public void onClick(View v) {
     86             int index = (Integer)v.getTag();
     87             uninstallApp(mPrefs.get(index));
     88         }
     89     };
     90 
     91     void makeCurrentHome(HomeAppPreference newHome) {
     92         if (mCurrentHome != null) {
     93             mCurrentHome.setChecked(false);
     94         }
     95         newHome.setChecked(true);
     96         mCurrentHome = newHome;
     97 
     98         mPm.replacePreferredActivity(mHomeFilter, IntentFilter.MATCH_CATEGORY_EMPTY,
     99                 mHomeComponentSet, newHome.activityName);
    100     }
    101 
    102     void uninstallApp(HomeAppPreference pref) {
    103         // Uninstallation is done by asking the OS to do it
    104        Uri packageURI = Uri.parse("package:" + pref.uninstallTarget);
    105        Intent uninstallIntent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE, packageURI);
    106        uninstallIntent.putExtra(Intent.EXTRA_UNINSTALL_ALL_USERS, false);
    107        int requestCode = REQUESTING_UNINSTALL + (pref.isChecked ? 1 : 0);
    108        startActivityForResult(uninstallIntent, requestCode);
    109    }
    110 
    111     @Override
    112     public void onActivityResult(int requestCode, int resultCode, Intent data) {
    113         super.onActivityResult(requestCode, resultCode, data);
    114 
    115         // Rebuild the list now that we might have nuked something
    116         buildHomeActivitiesList();
    117 
    118         // if the previous home app is now gone, fall back to the system one
    119         if (requestCode > REQUESTING_UNINSTALL) {
    120             // if mCurrentHome has gone null, it means we didn't find the previously-
    121             // default home app when rebuilding the list, i.e. it was the one we
    122             // just uninstalled.  When that happens we make the system-bundled
    123             // home app the active default.
    124             if (mCurrentHome == null) {
    125                 for (int i = 0; i < mPrefs.size(); i++) {
    126                     HomeAppPreference pref = mPrefs.get(i);
    127                     if (pref.isSystem) {
    128                         makeCurrentHome(pref);
    129                         break;
    130                     }
    131                 }
    132             }
    133         }
    134 
    135         // If we're down to just one possible home app, back out of this settings
    136         // fragment and show a dialog explaining to the user that they won't see
    137         // 'Home' settings now until such time as there are multiple available.
    138         if (mPrefs.size() < 2) {
    139             if (mShowNotice) {
    140                 mShowNotice = false;
    141                 Settings.requestHomeNotice();
    142             }
    143             finishFragment();
    144         }
    145     }
    146 
    147     void buildHomeActivitiesList() {
    148         ArrayList<ResolveInfo> homeActivities = new ArrayList<ResolveInfo>();
    149         ComponentName currentDefaultHome  = mPm.getHomeActivities(homeActivities);
    150 
    151         Context context = getActivity();
    152         mCurrentHome = null;
    153         mPrefGroup.removeAll();
    154         mPrefs = new ArrayList<HomeAppPreference>();
    155         mHomeComponentSet = new ComponentName[homeActivities.size()];
    156         int prefIndex = 0;
    157         for (int i = 0; i < homeActivities.size(); i++) {
    158             final ResolveInfo candidate = homeActivities.get(i);
    159             final ActivityInfo info = candidate.activityInfo;
    160             ComponentName activityName = new ComponentName(info.packageName, info.name);
    161             mHomeComponentSet[i] = activityName;
    162             try {
    163                 Drawable icon = info.loadIcon(mPm);
    164                 CharSequence name = info.loadLabel(mPm);
    165                 HomeAppPreference pref = new HomeAppPreference(context, activityName, prefIndex,
    166                         icon, name, this, info);
    167                 mPrefs.add(pref);
    168                 mPrefGroup.addPreference(pref);
    169                 pref.setEnabled(true);
    170                 if (activityName.equals(currentDefaultHome)) {
    171                     mCurrentHome = pref;
    172                 }
    173                 prefIndex++;
    174             } catch (Exception e) {
    175                 Log.v(TAG, "Problem dealing with activity " + activityName, e);
    176             }
    177         }
    178 
    179         if (mCurrentHome != null) {
    180             new Handler().post(new Runnable() {
    181                public void run() {
    182                    mCurrentHome.setChecked(true);
    183                }
    184             });
    185         }
    186     }
    187 
    188     @Override
    189     public void onCreate(Bundle savedInstanceState) {
    190         super.onCreate(savedInstanceState);
    191         addPreferencesFromResource(R.xml.home_selection);
    192 
    193         mPm = getPackageManager();
    194         mPrefGroup = (PreferenceGroup) findPreference("home");
    195 
    196         Bundle args = getArguments();
    197         mShowNotice = (args != null) && args.getBoolean(HOME_SHOW_NOTICE, false);
    198     }
    199 
    200     @Override
    201     public void onResume() {
    202         super.onResume();
    203         buildHomeActivitiesList();
    204     }
    205 
    206     class HomeAppPreference extends Preference {
    207         ComponentName activityName;
    208         int index;
    209         HomeSettings fragment;
    210         final ColorFilter grayscaleFilter;
    211         boolean isChecked;
    212 
    213         boolean isSystem;
    214         String uninstallTarget;
    215 
    216         public HomeAppPreference(Context context, ComponentName activity,
    217                 int i, Drawable icon, CharSequence title,
    218                 HomeSettings parent, ActivityInfo info) {
    219             super(context);
    220             setLayoutResource(R.layout.preference_home_app);
    221             setIcon(icon);
    222             setTitle(title);
    223             activityName = activity;
    224             fragment = parent;
    225             index = i;
    226 
    227             ColorMatrix colorMatrix = new ColorMatrix();
    228             colorMatrix.setSaturation(0f);
    229             float[] matrix = colorMatrix.getArray();
    230             matrix[18] = 0.5f;
    231             grayscaleFilter = new ColorMatrixColorFilter(colorMatrix);
    232 
    233             determineTargets(info);
    234         }
    235 
    236         // Check whether this activity is bundled on the system, with awareness
    237         // of the META_HOME_ALTERNATE mechanism.
    238         private void determineTargets(ActivityInfo info) {
    239             final Bundle meta = info.metaData;
    240             if (meta != null) {
    241                 final String altHomePackage = meta.getString(ActivityManager.META_HOME_ALTERNATE);
    242                 if (altHomePackage != null) {
    243                     try {
    244                         final int match = mPm.checkSignatures(info.packageName, altHomePackage);
    245                         if (match >= PackageManager.SIGNATURE_MATCH) {
    246                             PackageInfo altInfo = mPm.getPackageInfo(altHomePackage, 0);
    247                             final int altFlags = altInfo.applicationInfo.flags;
    248                             isSystem = (altFlags & ApplicationInfo.FLAG_SYSTEM) != 0;
    249                             uninstallTarget = altInfo.packageName;
    250                             return;
    251                         }
    252                     } catch (Exception e) {
    253                         // e.g. named alternate package not found during lookup
    254                         Log.w(TAG, "Unable to compare/resolve alternate", e);
    255                     }
    256                 }
    257             }
    258             // No suitable metadata redirect, so use the package's own info
    259             isSystem = (info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
    260             uninstallTarget = info.packageName;
    261         }
    262 
    263         @Override
    264         protected void onBindView(View view) {
    265             super.onBindView(view);
    266 
    267             RadioButton radio = (RadioButton) view.findViewById(R.id.home_radio);
    268             radio.setChecked(isChecked);
    269 
    270             Integer indexObj = new Integer(index);
    271 
    272             ImageView icon = (ImageView) view.findViewById(R.id.home_app_uninstall);
    273             if (isSystem) {
    274                 icon.setEnabled(false);
    275                 icon.setColorFilter(grayscaleFilter);
    276             } else {
    277                 icon.setOnClickListener(mDeleteClickListener);
    278                 icon.setTag(indexObj);
    279             }
    280 
    281             View v = view.findViewById(R.id.home_app_pref);
    282             v.setOnClickListener(mHomeClickListener);
    283             v.setTag(indexObj);
    284         }
    285 
    286         void setChecked(boolean state) {
    287             if (state != isChecked) {
    288                 isChecked = state;
    289                 notifyChanged();
    290             }
    291         }
    292     }
    293 }
    294