Home | History | Annotate | Download | only in settings
      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 }
    311