• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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