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 android.app.Activity; 20 import android.app.AlertDialog.Builder; 21 import android.content.Context; 22 import android.content.pm.ApplicationInfo; 23 import android.content.pm.PackageManager; 24 import android.content.pm.PackageManager.NameNotFoundException; 25 import android.graphics.drawable.Drawable; 26 import android.os.Parcel; 27 import android.os.Parcelable; 28 import android.preference.ListPreference; 29 import android.util.AttributeSet; 30 import android.view.LayoutInflater; 31 import android.view.View; 32 import android.view.ViewGroup; 33 import android.widget.ArrayAdapter; 34 import android.widget.ImageView; 35 import android.widget.ListAdapter; 36 import android.widget.TextView; 37 38 import java.util.ArrayList; 39 import java.util.List; 40 41 /** 42 * Extends ListPreference to allow us to show the icons for a given list of applications. We do this 43 * because the names of applications are very similar and the user may not be able to determine what 44 * app they are selecting without an icon. 45 */ 46 public class AppListPreference extends ListPreference { 47 48 public static final String ITEM_NONE_VALUE = ""; 49 50 private Drawable[] mEntryDrawables; 51 private boolean mShowItemNone = false; 52 53 public class AppArrayAdapter extends ArrayAdapter<CharSequence> { 54 private Drawable[] mImageDrawables = null; 55 private int mSelectedIndex = 0; 56 AppArrayAdapter(Context context, int textViewResourceId, CharSequence[] objects, Drawable[] imageDrawables, int selectedIndex)57 public AppArrayAdapter(Context context, int textViewResourceId, 58 CharSequence[] objects, Drawable[] imageDrawables, int selectedIndex) { 59 super(context, textViewResourceId, objects); 60 mSelectedIndex = selectedIndex; 61 mImageDrawables = imageDrawables; 62 } 63 64 @Override getView(int position, View convertView, ViewGroup parent)65 public View getView(int position, View convertView, ViewGroup parent) { 66 LayoutInflater inflater = ((Activity)getContext()).getLayoutInflater(); 67 View view = inflater.inflate(R.layout.app_preference_item, parent, false); 68 TextView textView = (TextView) view.findViewById(R.id.app_label); 69 textView.setText(getItem(position)); 70 if (position == mSelectedIndex) { 71 view.findViewById(R.id.default_label).setVisibility(View.VISIBLE); 72 } 73 ImageView imageView = (ImageView)view.findViewById(R.id.app_image); 74 imageView.setImageDrawable(mImageDrawables[position]); 75 return view; 76 } 77 } 78 AppListPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)79 public AppListPreference(Context context, AttributeSet attrs, 80 int defStyleAttr, int defStyleRes) { 81 super(context, attrs, defStyleAttr, defStyleRes); 82 } 83 AppListPreference(Context context, AttributeSet attrs)84 public AppListPreference(Context context, AttributeSet attrs) { 85 super(context, attrs); 86 } 87 setShowItemNone(boolean showItemNone)88 public void setShowItemNone(boolean showItemNone) { 89 mShowItemNone = showItemNone; 90 } 91 setPackageNames(CharSequence[] packageNames, CharSequence defaultPackageName)92 public void setPackageNames(CharSequence[] packageNames, CharSequence defaultPackageName) { 93 // Look up all package names in PackageManager. Skip ones we can't find. 94 PackageManager pm = getContext().getPackageManager(); 95 final int entryCount = packageNames.length + (mShowItemNone ? 1 : 0); 96 List<CharSequence> applicationNames = new ArrayList<>(entryCount); 97 List<CharSequence> validatedPackageNames = new ArrayList<>(entryCount); 98 List<Drawable> entryDrawables = new ArrayList<>(entryCount); 99 int selectedIndex = -1; 100 for (int i = 0; i < packageNames.length; i++) { 101 try { 102 ApplicationInfo appInfo = pm.getApplicationInfo(packageNames[i].toString(), 0); 103 applicationNames.add(appInfo.loadLabel(pm)); 104 validatedPackageNames.add(appInfo.packageName); 105 entryDrawables.add(appInfo.loadIcon(pm)); 106 if (defaultPackageName != null && 107 appInfo.packageName.contentEquals(defaultPackageName)) { 108 selectedIndex = i; 109 } 110 } catch (NameNotFoundException e) { 111 // Skip unknown packages. 112 } 113 } 114 115 if (mShowItemNone) { 116 applicationNames.add( 117 getContext().getResources().getText(R.string.app_list_preference_none)); 118 validatedPackageNames.add(ITEM_NONE_VALUE); 119 entryDrawables.add(getContext().getDrawable(R.drawable.ic_remove_circle)); 120 } 121 122 setEntries(applicationNames.toArray(new CharSequence[applicationNames.size()])); 123 setEntryValues( 124 validatedPackageNames.toArray(new CharSequence[validatedPackageNames.size()])); 125 mEntryDrawables = entryDrawables.toArray(new Drawable[entryDrawables.size()]); 126 127 if (selectedIndex != -1) { 128 setValueIndex(selectedIndex); 129 } else { 130 setValue(null); 131 } 132 } 133 createListAdapter()134 protected ListAdapter createListAdapter() { 135 final String selectedValue = getValue(); 136 final boolean selectedNone = selectedValue == null || 137 (mShowItemNone && selectedValue.contentEquals(ITEM_NONE_VALUE)); 138 int selectedIndex = selectedNone ? -1 : findIndexOfValue(selectedValue); 139 return new AppArrayAdapter(getContext(), 140 R.layout.app_preference_item, getEntries(), mEntryDrawables, selectedIndex); 141 } 142 143 @Override onPrepareDialogBuilder(Builder builder)144 protected void onPrepareDialogBuilder(Builder builder) { 145 builder.setAdapter(createListAdapter(), this); 146 super.onPrepareDialogBuilder(builder); 147 } 148 149 @Override onSaveInstanceState()150 protected Parcelable onSaveInstanceState() { 151 Parcelable superState = super.onSaveInstanceState(); 152 return new SavedState(getEntryValues(), getValue(), mShowItemNone, superState); 153 } 154 155 @Override onRestoreInstanceState(Parcelable state)156 protected void onRestoreInstanceState(Parcelable state) { 157 if (state instanceof SavedState) { 158 SavedState savedState = (SavedState) state; 159 mShowItemNone = savedState.showItemNone; 160 setPackageNames(savedState.entryValues, savedState.value); 161 super.onRestoreInstanceState(savedState.superState); 162 } else { 163 super.onRestoreInstanceState(state); 164 } 165 } 166 167 private static class SavedState implements Parcelable { 168 169 public final CharSequence[] entryValues; 170 public final CharSequence value; 171 public final boolean showItemNone; 172 public final Parcelable superState; 173 SavedState(CharSequence[] entryValues, CharSequence value, boolean showItemNone, Parcelable superState)174 public SavedState(CharSequence[] entryValues, CharSequence value, boolean showItemNone, 175 Parcelable superState) { 176 this.entryValues = entryValues; 177 this.value = value; 178 this.showItemNone = showItemNone; 179 this.superState = superState; 180 } 181 182 @Override describeContents()183 public int describeContents() { 184 return 0; 185 } 186 187 @Override writeToParcel(Parcel dest, int flags)188 public void writeToParcel(Parcel dest, int flags) { 189 dest.writeCharSequenceArray(entryValues); 190 dest.writeCharSequence(value); 191 dest.writeInt(showItemNone ? 1 : 0); 192 dest.writeParcelable(superState, flags); 193 } 194 195 public static Creator<SavedState> CREATOR = new Creator<SavedState>() { 196 @Override 197 public SavedState createFromParcel(Parcel source) { 198 CharSequence[] entryValues = source.readCharSequenceArray(); 199 CharSequence value = source.readCharSequence(); 200 boolean showItemNone = source.readInt() != 0; 201 Parcelable superState = source.readParcelable(getClass().getClassLoader()); 202 return new SavedState(entryValues, value, showItemNone, superState); 203 } 204 205 @Override 206 public SavedState[] newArray(int size) { 207 return new SavedState[size]; 208 } 209 }; 210 } 211 } 212