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