Android 系统设置中显示设置之休眠和屏保设置篇

时间:2024-03-10 16:10:23

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