Android 系统设置中显示设置之休眠和屏保设置篇
在上一篇中我们学习了Android系统设置中字体大小和屏幕旋转设置基本内容,在这一篇中我们继续学习显示设置中的休眠和屏保设置。
1、休眠设置
首先我们来看一下休眠设置在界面中的定义:
1 <ListPreference
2 android:key="screen_timeout"
3 android:title="@string/screen_timeout"
4 android:summary="@string/screen_timeout_summary"
5 android:persistent="false"
6 android:entries="@array/screen_timeout_entries" //当点击的时候弹出的listView显示的内容
7 android:entryValues="@array/screen_timeout_values" //listView显示的内容对应的时间
8 />
1 <string-array name="screen_timeout_entries">
2 <item msgid="3342301044271143016">"15 秒"</item>
3 <item msgid="8881760709354815449">"30 秒"</item>
4 <item msgid="7589406073232279088">"1 分钟"</item>
5 <item msgid="7001195990902244174">"2 分钟"</item>
6 <item msgid="7489864775127957179">"5 分钟"</item>
7 <item msgid="2314124409517439288">"10 分钟"</item>
8 <item msgid="6864027152847611413">"30 分钟"</item>
9 </string-array>
1 <!-- Do not translate. -->
2 <string-array name="screen_timeout_values" translatable="false">
3 <!-- Do not translate. -->
4 <item>15000</item>
5 <!-- Do not translate. -->
6 <item>30000</item>
7 <!-- Do not translate. -->
8 <item>60000</item>
9 <!-- Do not translate. -->
10 <item>120000</item>
11 <!-- Do not translate. -->
12 <item>300000</item>
13 <!-- Do not translate. -->
14 <item>600000</item>
15 <!-- Do not translate. -->
16 <item>1800000</item>
17 </string-array>
接下来我们看看DisplaySettings.java中休眠的相关代码:
1 mScreenTimeoutPreference = (ListPreference) findPreference(KEY_SCREEN_TIMEOUT);
2 //说明我们的休眠时间是保存在Settings.System中,如果获取不到,则默认值为FALLBACK_SCREEN_TIMEOUT_VALUE = 30000,也就是30秒
3 final long currentTimeout = Settings.System.getLong(resolver, SCREEN_OFF_TIMEOUT,
4 FALLBACK_SCREEN_TIMEOUT_VALUE);
5 mScreenTimeoutPreference.setValue(String.valueOf(currentTimeout));
6 mScreenTimeoutPreference.setOnPreferenceChangeListener(this);
7 //更新休眠时间列表
8 disableUnusableTimeouts(mScreenTimeoutPreference);
9 //修改值之后,更新summary的信息
10 updateTimeoutPreferenceDescription(currentTimeout);
至于disableUnusableTimeouts和updateTimeoutPreferenceDescription函数,是比较容易理解的,我这里就只是贴出代码。
1 private void updateTimeoutPreferenceDescription(long currentTimeout) {
2 ListPreference preference = mScreenTimeoutPreference;
3 String summary;
4 if (currentTimeout < 0) {
5 // Unsupported value
6 summary = "";
7 } else {
8 final CharSequence[] entries = preference.getEntries();
9 final CharSequence[] values = preference.getEntryValues();
10 if (entries == null || entries.length == 0) {
11 summary = "";
12 } else {
13 int best = 0;
14 for (int i = 0; i < values.length; i++) {
15 long timeout = Long.parseLong(values[i].toString());
16 if (currentTimeout >= timeout) {
17 best = i;
18 }
19 }
20 summary = preference.getContext().getString(R.string.screen_timeout_summary,
21 entries[best]);
22 }
23 }
24 preference.setSummary(summary);
25 }
26
27 private void disableUnusableTimeouts(ListPreference screenTimeoutPreference) {
28 final DevicePolicyManager dpm =
29 (DevicePolicyManager) getActivity().getSystemService(
30 Context.DEVICE_POLICY_SERVICE);
31 final long maxTimeout = dpm != null ? dpm.getMaximumTimeToLock(null) : 0;
32 if (maxTimeout == 0) {
33 return; // policy not enforced
34 }
35 final CharSequence[] entries = screenTimeoutPreference.getEntries();
36 final CharSequence[] values = screenTimeoutPreference.getEntryValues();
37 ArrayList<CharSequence> revisedEntries = new ArrayList<CharSequence>();
38 ArrayList<CharSequence> revisedValues = new ArrayList<CharSequence>();
39 for (int i = 0; i < values.length; i++) {
40 long timeout = Long.parseLong(values[i].toString());
41 if (timeout <= maxTimeout) {
42 revisedEntries.add(entries[i]);
43 revisedValues.add(values[i]);
44 }
45 }
46 if (revisedEntries.size() != entries.length || revisedValues.size() != values.length) {
47 final int userPreference = Integer.parseInt(screenTimeoutPreference.getValue());
48 screenTimeoutPreference.setEntries(
49 revisedEntries.toArray(new CharSequence[revisedEntries.size()]));
50 screenTimeoutPreference.setEntryValues(
51 revisedValues.toArray(new CharSequence[revisedValues.size()]));
52 if (userPreference <= maxTimeout) {
53 screenTimeoutPreference.setValue(String.valueOf(userPreference));
54 } else if (revisedValues.size() > 0
55 && Long.parseLong(revisedValues.get(revisedValues.size() - 1).toString())
56 == maxTimeout) {
57 // If the last one happens to be the same as the max timeout, select that
58 screenTimeoutPreference.setValue(String.valueOf(maxTimeout));
59 } else {
60 // There will be no highlighted selection since nothing in the list matches
61 // maxTimeout. The user can still select anything less than maxTimeout.
62 // TODO: maybe append maxTimeout to the list and mark selected.
63 }
64 }
65 screenTimeoutPreference.setEnabled(revisedEntries.size() > 0);
66 }
View Code
既然我们的休眠时间是从Settings.System中获取的,那我们又是怎么存的呢?
1 public boolean onPreferenceChange(Preference preference, Object objValue) {
2 final String key = preference.getKey();
3 if (KEY_SCREEN_TIMEOUT.equals(key)) {
4 int value = Integer.parseInt((String) objValue);
5 try {
6 Settings.System.putInt(getContentResolver(), SCREEN_OFF_TIMEOUT, value);
7 updateTimeoutPreferenceDescription(value);
8 } catch (NumberFormatException e) {
9 Log.e(TAG, "could not persist screen timeout setting", e);
10 }
11 }
12 if (KEY_FONT_SIZE.equals(key)) {
13 //该函数对字体进行设置
14 writeFontSizePreference(objValue);
15 }
16
17 return true;
18 }
有时候需要设备不进入休眠,我们只需要将SCREEN_OFF_TIMEOUT属性设置为-1即可。
Settings.System.putInt(getContentResolver(),android.provider.Settings.System.SCREEN_OFF_TIMEOUT, -1);
权限:<uses-permission android:name="android.permission.WRITE_SETTINGS" />
以上便是系统设置中休眠的相关内容。
2、屏幕保护
说完了休眠设置,我们接下来了解一下屏幕保护吧!首先来看看对应的布局:
1 <PreferenceScreen 2 android:key="screensaver" 3 android:title="@string/screensaver_settings_title" android:fragment="com.android.settings.DreamSettings" />
我们可以看到其中定义了android:fragment,也就是说当点击该item的时候会跳转到DreamSettings这个fragment。我们还是先看看DisplaySettings中有关屏保的代码吧!
1 mScreenSaverPreference = findPreference(KEY_SCREEN_SAVER);
2 //此处读取com.android.internal.R.bool.config_dreamsSupported的值,true表示支持屏保,false表示不支持
3 if (mScreenSaverPreference != null
4 && getResources().getBoolean(
5 com.android.internal.R.bool.config_dreamsSupported) == false) {
6 getPreferenceScreen().removePreference(mScreenSaverPreference);
7 }
那初始化的代码在哪里呢?
private void updateScreenSaverSummary() {
if (mScreenSaverPreference != null) {
mScreenSaverPreference.setSummary(
DreamSettings.getSummaryTextWithDreamName(getActivity()));//获取当前的屏保的名称
}
}
我们知道在定义屏保的时候指定了android:fragment属性,该属性的意思是当点击该preference时跳转到DreamSettings的fragment中,这里想问的是为什么这里指定了android:fragment就能跳转到对应的fragment呢? 原来在preference.java的构造函数中,保存了fragment这个成员变量,在PreferenceFragment中定了onPreferenceTreeClick函数,当preference点击的时候就会调用该函数,由于在preference中保存了fragment,所以会跳转到该fragment中。
1 /**
2 * {@inheritDoc}
3 */
4 public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen,
5 Preference preference) {
6 if (preference.getFragment() != null &&
7 getActivity() instanceof OnPreferenceStartFragmentCallback) {
8 return ((OnPreferenceStartFragmentCallback)getActivity()).onPreferenceStartFragment(
9 this, preference);
10 }
11 return false;
12 }
好的,刚刚解释了点击该preference为何能跳转到指定的fragment的原理。现在就让我们进入DreamSettings中一探究竟,Let's go!
首先找到onCreate函数,里面定义了一个控制打开关闭屏保的开关switch:
1 @Override
2 public void onCreate(Bundle icicle) {
3 logd("onCreate(%s)", icicle);
4 super.onCreate(icicle);
5 Activity activity = getActivity();
6
7 mBackend = new DreamBackend(activity);//对屏保的一个管理的类
8 mSwitch = new Switch(activity); //控制屏保是否打开的开关
9 mSwitch.setOnCheckedChangeListener(new OnCheckedChangeListener() {
10 @Override
11 public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
12 if (!mRefreshing) { //默认或者屏保刷新完毕即可进行下来的修改,否则跳过
13 mBackend.setEnabled(isChecked);//设置开关的状态
14 refreshFromBackend(); //刷新屏保信息
15 }
16 }
17 });
当屏保打开的时候,我们的界面是用listView进行显示的,listView的初始化是放在onActivityCreate中的,如下:
1 @Override
2 public void onActivityCreated(Bundle savedInstanceState) {
3 logd("onActivityCreated(%s)", savedInstanceState);
4 super.onActivityCreated(savedInstanceState);
5
6 ListView listView = getListView();
7
8 listView.setItemsCanFocus(true);
9
10 TextView emptyView = (TextView) getView().findViewById(android.R.id.empty);
11 emptyView.setText(R.string.screensaver_settings_disabled_prompt);
12 listView.setEmptyView(emptyView);
13
14 mAdapter = new DreamInfoAdapter(mContext);
15 listView.setAdapter(mAdapter);
16 }
View Code
屏保中还有两个菜单供用户进行选择,他们分别是开始播放和设置时间进行播放,这部分的代码:
1 @Override
2 public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
3 logd("onCreateOptionsMenu()");
4
5 boolean isEnabled = mBackend.isEnabled();
6
7 // create "start" action
8 MenuItem start = createMenuItem(menu, R.string.screensaver_settings_dream_start,
9 MenuItem.SHOW_AS_ACTION_ALWAYS,
10 isEnabled, new Runnable(){
11 @Override
12 public void run() {
13 mBackend.startDreaming();//调用錽tartDreaming进行屏保的播放
14 }});
15
16 // create "when to dream" overflow menu item
17 MenuItem whenToDream = createMenuItem(menu,
18 R.string.screensaver_settings_when_to_dream,
19 MenuItem.SHOW_AS_ACTION_IF_ROOM,
20 isEnabled,
21 new Runnable() {
22 @Override
23 public void run() {
24 showDialog(DIALOG_WHEN_TO_DREAM);//弹出对话框让用户设置时间进行播放
25 }});
26
27 // create "help" overflow menu item (make sure it appears last)
28 super.onCreateOptionsMenu(menu, inflater);
29
30 mMenuItemsWhenEnabled = new MenuItem[] { start, whenToDream };
31 }
View Code
接下来我们需要学习一下刷新的功能,refreshFromBackend函数:
1 private void refreshFromBackend() {
2 logd("refreshFromBackend()");
3 mRefreshing = true;
4 boolean dreamsEnabled = mBackend.isEnabled();
5 if (mSwitch.isChecked() != dreamsEnabled)
6 mSwitch.setChecked(dreamsEnabled);
7
8 mAdapter.clear();//清空列表
9 if (dreamsEnabled) {
10 List<DreamInfo> dreamInfos = mBackend.getDreamInfos();//通过getDreamInfos获取所有屏保信息
11 mAdapter.addAll(dreamInfos);//重新加载数据并调用notifyDataSetChanged进行刷新
12 }
13 if (mMenuItemsWhenEnabled != null)
14 for (MenuItem menuItem : mMenuItemsWhenEnabled)
15 menuItem.setEnabled(dreamsEnabled);
16 mRefreshing = false;
17 }
View Code
当然我们这里需要注意的是有时候我们的屏保是个apk,所以我们需要对apk卸载和安装进行监听,这样能够保证屏保的及时更新。这个操作的代码为:
1 @Override
2 public void onResume() {
3 logd("onResume()");
4 super.onResume();
5 refreshFromBackend();
6
7 // listen for package changes
8 IntentFilter filter = new IntentFilter();
9 filter.addAction(Intent.ACTION_PACKAGE_ADDED);//安装
10 filter.addAction(Intent.ACTION_PACKAGE_CHANGED);//改变
11 filter.addAction(Intent.ACTION_PACKAGE_REMOVED);//卸载
12 filter.addAction(Intent.ACTION_PACKAGE_REPLACED);//替换
13 filter.addDataScheme(PACKAGE_SCHEME);
14 mContext.registerReceiver(mPackageReceiver , filter);
15 }
16 private class PackageReceiver extends BroadcastReceiver {
17 @Override
18 public void onReceive(Context context, Intent intent) {
19 logd("PackageReceiver.onReceive");
20 refreshFromBackend();
21 }
22 }
以上就是屏保的设置内容。您的支持是我不懈的动力,当然不喜勿喷,希望与之交流!有错误或者错字的地方请指正,谢谢!
补充:这里有个重点没有介绍,那就是DreamBackend这个对屏保管理的类没有进行介绍,我这里只是将代码提供出来,感兴趣的朋友可以一起看看。
1 /*
2 * Copyright (C) 2012 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 static android.provider.Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK;
20 import static android.provider.Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP;
21 import static android.provider.Settings.Secure.SCREENSAVER_ENABLED;
22
23 import android.content.ComponentName;
24 import android.content.Context;
25 import android.content.Intent;
26 import android.content.pm.PackageManager;
27 import android.content.pm.ResolveInfo;
28 import android.content.pm.PackageManager.NameNotFoundException;
29 import android.content.pm.ServiceInfo;
30 import android.content.res.Resources;
31 import android.content.res.TypedArray;
32 import android.content.res.XmlResourceParser;
33 import android.graphics.drawable.Drawable;
34 import android.os.RemoteException;
35 import android.os.ServiceManager;
36 import android.provider.Settings;
37 import android.service.dreams.DreamService;
38 import android.service.dreams.IDreamManager;
39 import android.util.AttributeSet;
40 import android.util.Log;
41 import android.util.Xml;
42
43 import org.xmlpull.v1.XmlPullParser;
44 import org.xmlpull.v1.XmlPullParserException;
45
46 import java.io.IOException;
47 import java.util.ArrayList;
48 import java.util.Collections;
49 import java.util.Comparator;
50 import java.util.List;
51
52 public class DreamBackend {
53 private static final String TAG = DreamSettings.class.getSimpleName() + ".Backend";
54
55 public static class DreamInfo {
56 CharSequence caption;
57 Drawable icon;
58 boolean isActive;
59 public ComponentName componentName;
60 public ComponentName settingsComponentName;
61
62 @Override
63 public String toString() {
64 StringBuilder sb = new StringBuilder(DreamInfo.class.getSimpleName());
65 sb.append('[').append(caption);
66 if (isActive)
67 sb.append(",active");
68 sb.append(',').append(componentName);
69 if (settingsComponentName != null)
70 sb.append("settings=").append(settingsComponentName);
71 return sb.append(']').toString();
72 }
73 }
74
75 private final Context mContext;
76 private final IDreamManager mDreamManager;
77 private final DreamInfoComparator mComparator;
78 private final boolean mDreamsEnabledByDefault;
79 private final boolean mDreamsActivatedOnSleepByDefault;
80 private final boolean mDreamsActivatedOnDockByDefault;
81
82 public DreamBackend(Context context) {
83 mContext = context;
84 mDreamManager = IDreamManager.Stub.asInterface(
85 ServiceManager.getService(DreamService.DREAM_SERVICE));
86 mComparator = new DreamInfoComparator(getDefaultDream());
87 mDreamsEnabledByDefault = context.getResources()
88 .getBoolean(com.android.internal.R.bool.config_dreamsEnabledByDefault);
89 mDreamsActivatedOnSleepByDefault = context.getResources()
90 .getBoolean(com.android.internal.R.bool.config_dreamsActivatedOnSleepByDefault);
91 mDreamsActivatedOnDockByDefault = context.getResources()
92 .getBoolean(com.android.internal.R.bool.config_dreamsActivatedOnDockByDefault);
93 }
94
95 public List<DreamInfo> getDreamInfos() {
96 logd("getDreamInfos()");
97 ComponentName activeDream = getActiveDream();
98 PackageManager pm = mContext.getPackageManager();
99 Intent dreamIntent = new Intent(DreamService.SERVICE_INTERFACE);
100 List<ResolveInfo> resolveInfos = pm.queryIntentServices(dreamIntent,
101 PackageManager.GET_META_DATA);
102 List<DreamInfo> dreamInfos = new ArrayList<DreamInfo>(resolveInfos.size());
103 for (ResolveInfo resolveInfo : resolveInfos) {
104 if (resolveInfo.serviceInfo == null)
105 continue;
106 DreamInfo dreamInfo = new DreamInfo();
107 dreamInfo.caption = resolveInfo.loadLabel(pm);
108 dreamInfo.icon = resolveInfo.loadIcon(pm);
109 dreamInfo.componentName = getDreamComponentName(resolveInfo);
110 dreamInfo.isActive = dreamInfo.componentName.equals(activeDream);
111 dreamInfo.settingsComponentName = getSettingsComponentName(pm, resolveInfo);
112 dreamInfos.add(dreamInfo);
113 }
114 Collections.sort(dreamInfos, mComparator);
115 return dreamInfos;
116 }
117
118 public ComponentName getDefaultDream() {
119 if (mDreamManager == null)
120 return null;
121 try {
122 return mDreamManager.getDefaultDreamComponent();
123 } catch (RemoteException e) {
124 Log.w(TAG, "Failed to get default dream", e);
125 return null;
126 }
127 }
128
129 public CharSequence getActiveDreamName() {
130 ComponentName cn = getActiveDream();
131 if (cn != null) {
132 PackageManager pm = mContext.getPackageManager();
133 try {
134 ServiceInfo ri = pm.getServiceInfo(cn, 0);
135 if (ri != null) {
136 return ri.loadLabel(pm);
137 }
138 } catch (PackageManager.NameNotFoundException exc) {
139 return null; // uninstalled?
140 }
141 }
142 return null;
143 }
144
145 public boolean isEnabled() {
146 return getBoolean(SCREENSAVER_ENABLED, mDreamsEnabledByDefault);
147 }
148
149 public void setEnabled(boolean value) {
150 logd("setEnabled(%s)", value);
151 setBoolean(SCREENSAVER_ENABLED, value);
152 }
153
154 public boolean isActivatedOnDock() {
155 return getBoolean(SCREENSAVER_ACTIVATE_ON_DOCK, mDreamsActivatedOnDockByDefault);
156 }
157
158 public void setActivatedOnDock(boolean value) {
159 logd("setActivatedOnDock(%s)", value);
160 setBoolean(SCREENSAVER_ACTIVATE_ON_DOCK, value);
161 }
162
163 public boolean isActivatedOnSleep() {
164 return getBoolean(SCREENSAVER_ACTIVATE_ON_SLEEP, mDreamsActivatedOnSleepByDefault);
165 }
166
167 public void setActivatedOnSleep(boolean value) {
168 logd("setActivatedOnSleep(%s)", value);
169 setBoolean(SCREENSAVER_ACTIVATE_ON_SLEEP, value);
170 }
171
172 private boolean getBoolean(String key, boolean def) {
173 return Settings.Secure.getInt(mContext.getContentResolver(), key, def ? 1 : 0) == 1;
174 }
175
176 private void setBoolean(String key, boolean value) {
177 Settings.Secure.putInt(mContext.getContentResolver(), key, value ? 1 : 0);
178 }
179
180 public void setActiveDream(ComponentName dream) {
181 logd("setActiveDream(%s)", dream);
182 if (mDreamManager == null)
183 return;
184 try {
185 ComponentName[] dreams = { dream };
186 mDreamManager.setDreamComponents(dream == null ? null : dreams);
187 } catch (RemoteException e) {
188 Log.w(TAG, "Failed to set active dream to " + dream, e);
189 }
190 }
191
192 public ComponentName getActiveDream() {
193 if (mDreamManager == null)
194 return null;
195 try {
196 ComponentName[] dreams = mDreamManager.getDreamComponents();
197 return dreams != null && dreams.length > 0 ? dreams[0] : null;
198 } catch (RemoteException e) {
199 Log.w(TAG, "Failed to get active dream", e);
200 return null;
201 }
202 }
203
204 public void launchSettings(DreamInfo dreamInfo) {
205 logd("launchSettings(%s)", dreamInfo);
206 if (dreamInfo == null || dreamInfo.settingsComponentName == null)
207 return;
208 mContext.startActivity(new Intent().setComponent(dreamInfo.settingsComponentName));
209 }
210
211 public void preview(DreamInfo dreamInfo) {
212 logd("preview(%s)", dreamInfo);
213 if (mDreamManager == null || dreamInfo == null || dreamInfo.componentName == null)
214 return;
215 try {
216 mDreamManager.testDream(dreamInfo.componentName);
217 } catch (RemoteException e) {
218 Log.w(TAG, "Failed to preview " + dreamInfo, e);
219 }
220 }
221
222 public void startDreaming() {
223 logd("startDreaming()");
224 if (mDreamManager == null)
225 return;
226 try {
227 mDreamManager.dream();
228 } catch (RemoteException e) {
229 Log.w(TAG, "Failed to dream", e);
230 }
231 }
232
233 private static ComponentName getDreamComponentName(ResolveInfo resolveInfo) {
234 if (resolveInfo == null || resolveInfo.serviceInfo == null)
235 return null;
236 return new ComponentName(resolveInfo.serviceInfo.packageName, resolveInfo.serviceInfo.name);
237 }
238
239 private static ComponentName getSettingsComponentName(PackageManager pm, ResolveInfo resolveInfo) {
240 if (resolveInfo == null
241 || resolveInfo.serviceInfo == null
242 || resolveInfo.serviceInfo.metaData == null)
243 return null;
244 String cn = null;
245 XmlResourceParser parser = null;
246 Exception caughtException = null;
247 try {
248 parser = resolveInfo.serviceInfo.loadXmlMetaData(pm, DreamService.DREAM_META_DATA);
249 if (parser == null) {
250 Log.w(TAG, "No " + DreamService.DREAM_META_DATA + " meta-data");
251 return null;
252 }
253 Resources res = pm.getResourcesForApplication(resolveInfo.serviceInfo.applicationInfo);
254 AttributeSet attrs = Xml.asAttributeSet(parser);
255 int type;
256 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
257 && type != XmlPullParser.START_TAG) {
258 }
259 String nodeName = parser.getName();
260 if (!"dream".equals(nodeName)) {
261 Log.w(TAG, "Meta-data does not start with dream tag");
262 return null;
263 }
264 TypedArray sa = res.obtainAttributes(attrs, com.android.internal.R.styleable.Dream);
265 cn = sa.getString(com.android.internal.R.styleable.Dream_settingsActivity);
266 sa.recycle();
267 } catch (NameNotFoundException e) {
268 caughtException = e;
269 } catch (IOException e) {
270 caughtException = e;
271 } catch (XmlPullParserException e) {
272 caughtException = e;
273 } finally {
274 if (parser != null) parser.close();
275 }
276 if (caughtException != null) {
277 Log.w(TAG, "Error parsing : " + resolveInfo.serviceInfo.packageName, caughtException);
278 return null;
279 }
280 if (cn != null && cn.indexOf('/') < 0) {
281 cn = resolveInfo.serviceInfo.packageName + "/" + cn;
282 }
283 return cn == null ? null : ComponentName.unflattenFromString(cn);
284 }
285
286 private static void logd(String msg, Object... args) {
287 if (DreamSettings.DEBUG)
288 Log.d(TAG, args == null || args.length == 0 ? msg : String.format(msg, args));
289 }
290
291 private static class DreamInfoComparator implements Comparator<DreamInfo> {
292 private final ComponentName mDefaultDream;
293
294 public DreamInfoComparator(ComponentName defaultDream) {
295 mDefaultDream = defaultDream;
296 }
297
298 @Override
299 public int compare(DreamInfo lhs, DreamInfo rhs) {
300 return sortKey(lhs).compareTo(sortKey(rhs));
301 }
302
303 private String sortKey(DreamInfo di) {
304 StringBuilder sb = new StringBuilder();
305 sb.append(di.componentName.equals(mDefaultDream) ? '0' : '1');
306 sb.append(di.caption);
307 return sb.toString();
308 }
309 }
310 }
View Code