1f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout/*
2f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout * Copyright (C) 2015 The Android Open Source Project
3f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout *
4f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout * Licensed under the Apache License, Version 2.0 (the "License");
5f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout * you may not use this file except in compliance with the License.
6f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout * You may obtain a copy of the License at
7f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout *
8f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout *      http://www.apache.org/licenses/LICENSE-2.0
9f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout *
10f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout * Unless required by applicable law or agreed to in writing, software
11f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout * distributed under the License is distributed on an "AS IS" BASIS,
12f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout * See the License for the specific language governing permissions and
14f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout * limitations under the License
15f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout */
16f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout
17f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stoutpackage android.support.v17.leanback.system;
18f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout
19f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stoutimport android.content.Context;
20f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stoutimport android.content.Intent;
21f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stoutimport android.content.pm.ApplicationInfo;
22f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stoutimport android.content.pm.PackageManager;
23f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stoutimport android.content.pm.ResolveInfo;
24f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stoutimport android.content.res.Resources;
25f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stoutimport android.support.v17.leanback.widget.ShadowOverlayContainer;
26f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stoutimport android.util.Log;
27f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout
28f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout/**
29f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout * Provides various preferences affecting Leanback runtime behavior.
30f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout * <p>Note this class is not thread safe and its methods should only
31f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout * be invoked from the UI thread
32f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout * </p>
33f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout */
34f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stoutpublic class Settings {
35f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout    static private final String TAG = "Settings";
36f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout    static private final boolean DEBUG = false;
37f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout
38f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout    // The intent action that must be provided by a broadcast receiver
39f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout    // in a customization package.
40f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout    private static final String ACTION_PARTNER_CUSTOMIZATION =
41f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout            "android.support.v17.leanback.action.PARTNER_CUSTOMIZATION";
42f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout
43f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout    static public final String PREFER_STATIC_SHADOWS = "PREFER_STATIC_SHADOWS";
44f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout
45f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout    static private Settings sInstance;
46f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout
47f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout    private boolean mPreferStaticShadows;
48f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout
49f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout    /**
50f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout     * Returns the singleton Settings instance.
51f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout     */
52f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout    static public Settings getInstance(Context context) {
53f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout        if (sInstance == null) {
54f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout            sInstance = new Settings(context);
55f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout        }
56f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout        return sInstance;
57f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout    }
58f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout
59f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout    private Settings(Context context) {
60f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout        if (DEBUG) Log.v(TAG, "generating preferences");
61f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout        Customizations customizations = getCustomizations(context);
62f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout        generateShadowSetting(customizations);
63f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout    }
64f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout
65f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout    /**
66f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout     * Returns true if static shadows are recommended.
67f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout     * @hide
68f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout     */
69f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout    public boolean preferStaticShadows() {
70f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout        return mPreferStaticShadows;
71f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout    }
72f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout
73f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout    /**
74f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout     * Returns the boolean preference for the given key.
75f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout     */
76f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout    public boolean getBoolean(String key) {
77f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout        return getOrSetBoolean(key, false, false);
78f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout    }
79f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout
80f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout    /**
81f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout     * Sets the boolean preference for the given key.  If an app uses this api to override
82f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout     * a default preference, it must do so on every activity create.
83f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout     */
84f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout    public void setBoolean(String key, boolean value) {
85f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout        getOrSetBoolean(key, true, value);
86f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout    }
87f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout
88f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout    boolean getOrSetBoolean(String key, boolean set, boolean value) {
89f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout        if (key.compareTo(PREFER_STATIC_SHADOWS) == 0) {
90f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout            return set ? (mPreferStaticShadows = value) : mPreferStaticShadows;
91f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout        }
92f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout        throw new IllegalArgumentException("Invalid key");
93f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout    }
94f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout
95f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout    private void generateShadowSetting(Customizations customizations) {
96f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout        if (ShadowOverlayContainer.supportsDynamicShadow()) {
97f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout            mPreferStaticShadows = false;
98f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout            if (customizations != null) {
99f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout                mPreferStaticShadows = customizations.getBoolean(
100f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout                        "leanback_prefer_static_shadows", mPreferStaticShadows);
101f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout            }
102f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout        } else {
103f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout            mPreferStaticShadows = true;
104f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout        }
105f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout
106f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout        if (DEBUG) Log.v(TAG, "generated preference " + PREFER_STATIC_SHADOWS + ": "
107f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout                + mPreferStaticShadows);
108f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout    }
109f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout
110f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout    static class Customizations {
111f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout        Resources mResources;
112f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout        String mPackageName;
113f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout
114f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout        public Customizations(Resources resources, String packageName) {
115f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout            mResources = resources;
116f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout            mPackageName = packageName;
117f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout        }
118f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout
119f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout        public boolean getBoolean(String resourceName, boolean defaultValue) {
120f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout            int resId = mResources.getIdentifier(resourceName, "bool", mPackageName);
121f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout            return resId > 0 ? mResources.getBoolean(resId) : defaultValue;
122f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout        }
123f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout    };
124f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout
125f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout    private Customizations getCustomizations(Context context) {
126f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout        final PackageManager pm = context.getPackageManager();
127f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout        final Intent intent = new Intent(ACTION_PARTNER_CUSTOMIZATION);
128f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout        if (DEBUG) Log.v(TAG, "getting oem customizations by intent: " +
129f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout                ACTION_PARTNER_CUSTOMIZATION);
130f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout
131f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout        Resources resources = null;
132f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout        String packageName = null;
133f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout        for (ResolveInfo info : pm.queryBroadcastReceivers(intent, 0)) {
134f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout            packageName = info.activityInfo.packageName;
135f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout            if (DEBUG) Log.v(TAG, "got package " + packageName);
136f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout            if (packageName != null && isSystemApp(info)) try {
137f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout                resources = pm.getResourcesForApplication(packageName);
138f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout            } catch (PackageManager.NameNotFoundException ex) {
139f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout                // Do nothing
140f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout            }
141f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout            if (resources != null) {
142f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout                if (DEBUG) Log.v(TAG, "found customization package: " + packageName);
143f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout                break;
144f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout            }
145f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout        }
146f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout        return resources == null ? null : new Customizations(resources, packageName);
147f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout    }
148f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout
149f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout    private static boolean isSystemApp(ResolveInfo info) {
150f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout        return (info.activityInfo != null &&
151f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout                (info.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0);
152f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout    }
153f4acd3cf076435ce836a6d4a9027b73ec3050defCraig Stout}
154