1/*
2 * Copyright (C) 2015 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
17package com.android.settings.applications;
18
19import android.content.Context;
20import android.content.Intent;
21import android.content.pm.PackageManager;
22import android.content.pm.ResolveInfo;
23import android.net.Uri;
24import android.os.Bundle;
25import android.os.Handler;
26import android.os.UserHandle;
27import android.os.UserManager;
28import android.preference.Preference;
29import android.provider.SearchIndexableResource;
30import android.text.TextUtils;
31import android.util.Log;
32
33import com.android.internal.content.PackageMonitor;
34import com.android.internal.logging.MetricsLogger;
35import com.android.settings.InstrumentedFragment;
36import com.android.settings.R;
37import com.android.settings.SettingsPreferenceFragment;
38import com.android.settings.search.BaseSearchIndexProvider;
39import com.android.settings.search.Index;
40import com.android.settings.search.Indexable;
41
42import java.util.ArrayList;
43import java.util.Arrays;
44import java.util.List;
45
46public class ManageDefaultApps extends SettingsPreferenceFragment
47        implements Preference.OnPreferenceClickListener, Indexable {
48
49    private static final String TAG = ManageDefaultApps.class.getSimpleName();
50
51    private static final String KEY_DEFAULT_BROWSER = "default_browser";
52    private static final String KEY_DEFAULT_PHONE_APP = "default_phone_app";
53    private static final String KEY_DEFAULT_EMERGENCY_APP = "default_emergency_app";
54    private static final String KEY_SMS_APPLICATION = "default_sms_app";
55
56    private DefaultBrowserPreference mDefaultBrowserPreference;
57    private PackageManager mPm;
58    private int myUserId;
59
60    private static final long DELAY_UPDATE_BROWSER_MILLIS = 500;
61
62    private final Handler mHandler = new Handler();
63
64    private final Runnable mUpdateRunnable = new Runnable() {
65        @Override
66        public void run() {
67            updateDefaultBrowserPreference();
68        }
69    };
70
71    private final PackageMonitor mPackageMonitor = new PackageMonitor() {
72        @Override
73        public void onPackageAdded(String packageName, int uid) {
74            sendUpdate();
75        }
76
77        @Override
78        public void onPackageAppeared(String packageName, int reason) {
79            sendUpdate();
80        }
81
82        @Override
83        public void onPackageDisappeared(String packageName, int reason) {
84            sendUpdate();
85        }
86
87        @Override
88        public void onPackageRemoved(String packageName, int uid) {
89            sendUpdate();
90        }
91
92        private void sendUpdate() {
93            mHandler.postDelayed(mUpdateRunnable, DELAY_UPDATE_BROWSER_MILLIS);
94        }
95    };
96
97    private void updateDefaultBrowserPreference() {
98        mDefaultBrowserPreference.refreshBrowserApps();
99
100        final PackageManager pm = getPackageManager();
101
102        String packageName = pm.getDefaultBrowserPackageName(UserHandle.myUserId());
103        if (!TextUtils.isEmpty(packageName)) {
104            // Check if the default Browser package is still there
105            Intent intent = new Intent();
106            intent.setPackage(packageName);
107            intent.setAction(Intent.ACTION_VIEW);
108            intent.addCategory(Intent.CATEGORY_BROWSABLE);
109            intent.setData(Uri.parse("http:"));
110
111            ResolveInfo info = mPm.resolveActivityAsUser(intent, 0, myUserId);
112            if (info != null) {
113                mDefaultBrowserPreference.setValue(packageName);
114                CharSequence label = info.loadLabel(pm);
115                mDefaultBrowserPreference.setSummary(label);
116            } else {
117                mDefaultBrowserPreference.setSummary(R.string.default_browser_title_none);
118            }
119        } else {
120            mDefaultBrowserPreference.setSummary(R.string.default_browser_title_none);
121            Log.d(TAG, "Cannot set empty default Browser value!");
122        }
123    }
124
125    @Override
126    public void onCreate(Bundle icicle) {
127        super.onCreate(icicle);
128
129        addPreferencesFromResource(R.xml.default_apps);
130
131        mPm = getPackageManager();
132        myUserId = UserHandle.myUserId();
133
134        mDefaultBrowserPreference = (DefaultBrowserPreference) findPreference(KEY_DEFAULT_BROWSER);
135        mDefaultBrowserPreference.setOnPreferenceChangeListener(
136                new Preference.OnPreferenceChangeListener() {
137                    @Override
138                    public boolean onPreferenceChange(Preference preference, Object newValue) {
139                        if (newValue == null) {
140                            return false;
141                        }
142                        final CharSequence packageName = (CharSequence) newValue;
143                        if (TextUtils.isEmpty(packageName)) {
144                            return false;
145                        }
146                        boolean result = mPm.setDefaultBrowserPackageName(
147                                packageName.toString(), myUserId);
148                        if (result) {
149                            mDefaultBrowserPreference.setValue(packageName.toString());
150                            final CharSequence appName = mDefaultBrowserPreference.getEntry();
151                            mDefaultBrowserPreference.setSummary(appName);
152                        }
153                        return result;
154                    }
155        });
156        final boolean isRestrictedUser = UserManager.get(getActivity())
157                .getUserInfo(myUserId).isRestricted();
158
159        // Restricted users cannot currently read/write SMS.
160        // Remove SMS Application if the device does not support SMS
161        if (isRestrictedUser || !DefaultSmsPreference.isAvailable(getActivity())) {
162            removePreference(KEY_SMS_APPLICATION);
163        }
164
165        if (!DefaultPhonePreference.isAvailable(getActivity())) {
166            removePreference(KEY_DEFAULT_PHONE_APP);
167        }
168
169        if (!DefaultEmergencyPreference.isAvailable(getActivity())) {
170            removePreference(KEY_DEFAULT_EMERGENCY_APP);
171        }
172
173        if (DefaultEmergencyPreference.isCapable(getActivity())) {
174            Index.getInstance(getActivity()).updateFromClassNameResource(
175                    ManageDefaultApps.class.getName(), true, true);
176        }
177    }
178
179    @Override
180    public void onResume() {
181        super.onResume();
182        updateDefaultBrowserPreference();
183        mPackageMonitor.register(getActivity(), getActivity().getMainLooper(), false);
184    }
185
186    @Override
187    public void onPause() {
188        super.onPause();
189
190        mPackageMonitor.unregister();
191    }
192
193    @Override
194    protected int getMetricsCategory() {
195        return MetricsLogger.APPLICATIONS_DEFAULT_APPS;
196    }
197
198    @Override
199    public boolean onPreferenceClick(Preference preference) {
200        return false;
201    }
202
203    public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
204        new BaseSearchIndexProvider() {
205            @Override
206            public List<SearchIndexableResource> getXmlResourcesToIndex(
207                    Context context, boolean enabled) {
208                SearchIndexableResource sir = new SearchIndexableResource(context);
209                sir.xmlResId = R.xml.default_apps;
210                return Arrays.asList(sir);
211            }
212
213            @Override
214            public List<String> getNonIndexableKeys(Context context) {
215                final ArrayList<String> result = new ArrayList<String>();
216
217                // Remove SMS Application if the device does not support SMS
218                final boolean isRestrictedUser = UserManager.get(context)
219                        .getUserInfo(UserHandle.myUserId()).isRestricted();
220                if (!DefaultSmsPreference.isAvailable(context) || isRestrictedUser) {
221                    result.add(KEY_SMS_APPLICATION);
222                }
223
224                if (!DefaultEmergencyPreference.isAvailable(context)) {
225                    result.add(KEY_DEFAULT_EMERGENCY_APP);
226                }
227
228                return result;
229            }
230    };
231}
232