ManageDomainUrls.java revision 26e5760033c5c3d4f64a0cb34e436fdd95bf7e68
1/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
5 * except in compliance with the License. You may obtain a copy of the License at
6 *
7 *      http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software distributed under the
10 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
11 * KIND, either express or implied. See the License for the specific language governing
12 * permissions and limitations under the License.
13 */
14
15package com.android.settings.applications;
16
17import android.app.Application;
18import android.content.Context;
19import android.content.pm.PackageManager;
20import android.os.Bundle;
21import android.os.UserHandle;
22import android.provider.Settings;
23import android.provider.Settings.Global;
24import android.support.v14.preference.SwitchPreference;
25import android.support.v7.preference.Preference;
26import android.support.v7.preference.Preference.OnPreferenceChangeListener;
27import android.support.v7.preference.Preference.OnPreferenceClickListener;
28import android.support.v7.preference.PreferenceCategory;
29import android.support.v7.preference.PreferenceGroup;
30import android.support.v7.preference.PreferenceViewHolder;
31import android.util.ArraySet;
32import android.view.View;
33
34import com.android.internal.logging.MetricsProto.MetricsEvent;
35import com.android.settings.R;
36import com.android.settings.SettingsPreferenceFragment;
37import com.android.settings.Utils;
38import com.android.settingslib.applications.ApplicationsState;
39import com.android.settingslib.applications.ApplicationsState.AppEntry;
40
41import java.util.ArrayList;
42
43/**
44 * Activity to manage how Android handles URL resolution. Includes both per-app
45 * handling as well as system handling for Web Actions.
46 */
47public class ManageDomainUrls extends SettingsPreferenceFragment
48        implements ApplicationsState.Callbacks, OnPreferenceChangeListener,
49        OnPreferenceClickListener {
50
51    // constant value that can be used to check return code from sub activity.
52    private static final int INSTALLED_APP_DETAILS = 1;
53
54    private ApplicationsState mApplicationsState;
55    private ApplicationsState.Session mSession;
56    private PreferenceGroup mDomainAppList;
57    private SwitchPreference mWebAction;
58
59    @Override
60    public void onCreate(Bundle icicle) {
61        super.onCreate(icicle);
62        setAnimationAllowed(true);
63        setPreferenceScreen(getPreferenceManager().createPreferenceScreen(getContext()));
64        mApplicationsState = ApplicationsState.getInstance(
65                (Application) getContext().getApplicationContext());
66        mSession = mApplicationsState.newSession(this);
67        setHasOptionsMenu(true);
68    }
69
70    @Override
71    public void onViewCreated(View view, Bundle savedInstanceState) {
72        super.onViewCreated(view, savedInstanceState);
73    }
74
75    @Override
76    public void onResume() {
77        super.onResume();
78        mSession.resume();
79    }
80
81    @Override
82    public void onPause() {
83        super.onPause();
84        mSession.pause();
85    }
86
87    @Override
88    public void onDestroy() {
89        super.onDestroy();
90        mSession.release();
91    }
92
93    @Override
94    public void onRunningStateChanged(boolean running) {
95    }
96
97    @Override
98    public void onPackageListChanged() {
99    }
100
101    @Override
102    public void onRebuildComplete(ArrayList<AppEntry> apps) {
103        if (getContext() == null) {
104            return;
105        }
106
107        final boolean disableWebActions = Global.getInt(getContext().getContentResolver(),
108                Global.ENABLE_EPHEMERAL_FEATURE, 1) == 0;
109        if (disableWebActions) {
110            mDomainAppList = getPreferenceScreen();
111        } else {
112            final PreferenceGroup preferenceScreen = getPreferenceScreen();
113            if (preferenceScreen.getPreferenceCount() == 0) {
114                // add preferences
115                final PreferenceCategory webActionCategory =
116                        new PreferenceCategory(getPrefContext());
117                webActionCategory.setTitle(R.string.web_action_section_title);
118                preferenceScreen.addPreference(webActionCategory);
119
120                // toggle to enable / disable Web Actions [aka Instant Apps]
121                mWebAction = new SwitchPreference(getPrefContext());
122                mWebAction.setTitle(R.string.web_action_enable_title);
123                mWebAction.setSummary(R.string.web_action_enable_summary);
124                mWebAction.setChecked(Settings.Secure.getInt(getContentResolver(),
125                        Settings.Secure.WEB_ACTION_ENABLED, 1) != 0);
126                mWebAction.setOnPreferenceChangeListener(this);
127                webActionCategory.addPreference(mWebAction);
128
129                // list to manage link handling per app
130                mDomainAppList = new PreferenceCategory(getPrefContext());
131                mDomainAppList.setTitle(R.string.domain_url_section_title);
132                preferenceScreen.addPreference(mDomainAppList);
133            }
134        }
135        rebuildAppList(mDomainAppList, apps);
136    }
137
138    @Override
139    public boolean onPreferenceChange(Preference preference, Object newValue) {
140        if (preference == mWebAction) {
141            final int enabled = (boolean) newValue ? 1 : 0;
142            Settings.Secure.putInt(
143                    getContentResolver(), Settings.Secure.WEB_ACTION_ENABLED, enabled);
144            return true;
145        }
146        return false;
147    }
148
149    private void rebuild() {
150        final ArrayList<AppEntry> apps = mSession.rebuild(
151                ApplicationsState.FILTER_WITH_DOMAIN_URLS, ApplicationsState.ALPHA_COMPARATOR);
152        if (apps != null) {
153            onRebuildComplete(apps);
154        }
155    }
156
157    private void rebuildAppList(PreferenceGroup group, ArrayList<AppEntry> apps) {
158        cacheRemoveAllPrefs(group);
159        final int N = apps.size();
160        for (int i = 0; i < N; i++) {
161            AppEntry entry = apps.get(i);
162            String key = entry.info.packageName + "|" + entry.info.uid;
163            DomainAppPreference preference = (DomainAppPreference) getCachedPreference(key);
164            if (preference == null) {
165                preference = new DomainAppPreference(getPrefContext(), entry);
166                preference.setKey(key);
167                preference.setOnPreferenceClickListener(this);
168                group.addPreference(preference);
169            } else {
170                preference.reuse();
171            }
172            preference.setOrder(i);
173        }
174        removeCachedPrefs(group);
175    }
176
177    @Override
178    public void onPackageIconChanged() {
179    }
180
181    @Override
182    public void onPackageSizeChanged(String packageName) {
183    }
184
185    @Override
186    public void onAllSizesComputed() {
187    }
188
189    @Override
190    public void onLauncherInfoChanged() {
191    }
192
193    @Override
194    public void onLoadEntriesCompleted() {
195        rebuild();
196    }
197
198    @Override
199    protected int getMetricsCategory() {
200        return MetricsEvent.MANAGE_DOMAIN_URLS;
201    }
202
203    @Override
204    public boolean onPreferenceClick(Preference preference) {
205        if (preference.getClass() == DomainAppPreference.class) {
206            ApplicationsState.AppEntry entry = ((DomainAppPreference) preference).mEntry;
207            AppInfoBase.startAppInfoFragment(AppLaunchSettings.class, R.string.auto_launch_label,
208                    entry.info.packageName, entry.info.uid, this,
209                    INSTALLED_APP_DETAILS);
210            return true;
211        }
212        return false;
213    }
214
215    private class DomainAppPreference extends Preference {
216        private final AppEntry mEntry;
217        private final PackageManager mPm;
218
219        public DomainAppPreference(final Context context, AppEntry entry) {
220            super(context);
221            mPm = context.getPackageManager();
222            mEntry = entry;
223            mEntry.ensureLabel(getContext());
224            setState();
225            if (mEntry.icon != null) {
226                setIcon(mEntry.icon);
227            }
228        }
229
230        private void setState() {
231            setTitle(mEntry.label);
232            setSummary(getDomainsSummary(mEntry.info.packageName));
233        }
234
235        public void reuse() {
236            setState();
237            notifyChanged();
238        }
239
240        @Override
241        public void onBindViewHolder(PreferenceViewHolder holder) {
242            if (mEntry.icon == null) {
243                holder.itemView.post(new Runnable() {
244                    @Override
245                    public void run() {
246                        // Ensure we have an icon before binding.
247                        mApplicationsState.ensureIcon(mEntry);
248                        // This might trigger us to bind again, but it gives an easy way to only
249                        // load the icon once its needed, so its probably worth it.
250                        setIcon(mEntry.icon);
251                    }
252                });
253            }
254            super.onBindViewHolder(holder);
255        }
256
257        private CharSequence getDomainsSummary(String packageName) {
258            // If the user has explicitly said "no" for this package, that's the
259            // string we should show.
260            int domainStatus =
261                    mPm.getIntentVerificationStatusAsUser(packageName, UserHandle.myUserId());
262            if (domainStatus == PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER) {
263                return getContext().getString(R.string.domain_urls_summary_none);
264            }
265            // Otherwise, ask package manager for the domains for this package,
266            // and show the first one (or none if there aren't any).
267            ArraySet<String> result = Utils.getHandledDomains(mPm, packageName);
268            if (result.size() == 0) {
269                return getContext().getString(R.string.domain_urls_summary_none);
270            } else if (result.size() == 1) {
271                return getContext().getString(R.string.domain_urls_summary_one, result.valueAt(0));
272            } else {
273                return getContext().getString(R.string.domain_urls_summary_some, result.valueAt(0));
274            }
275        }
276    }
277}
278