• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
15 package com.android.settings.applications;
16 
17 import android.app.Application;
18 import android.content.ComponentName;
19 import android.content.Context;
20 import android.content.Intent;
21 import android.content.pm.PackageManager;
22 import android.os.Bundle;
23 import android.os.UserHandle;
24 import android.provider.Settings;
25 import android.provider.Settings.Global;
26 import android.support.annotation.VisibleForTesting;
27 import android.support.v14.preference.SwitchPreference;
28 import android.support.v7.preference.Preference;
29 import android.support.v7.preference.Preference.OnPreferenceChangeListener;
30 import android.support.v7.preference.Preference.OnPreferenceClickListener;
31 import android.support.v7.preference.PreferenceCategory;
32 import android.support.v7.preference.PreferenceGroup;
33 import android.support.v7.preference.PreferenceViewHolder;
34 import android.util.ArraySet;
35 import android.view.View;
36 
37 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
38 import com.android.settings.R;
39 import com.android.settings.SettingsPreferenceFragment;
40 import com.android.settings.Utils;
41 import com.android.settings.widget.AppPreference;
42 import com.android.settingslib.applications.ApplicationsState;
43 import com.android.settingslib.applications.ApplicationsState.AppEntry;
44 
45 import java.util.ArrayList;
46 
47 /**
48  * Activity to manage how Android handles URL resolution. Includes both per-app
49  * handling as well as system handling for Web Actions.
50  */
51 public class ManageDomainUrls extends SettingsPreferenceFragment
52         implements ApplicationsState.Callbacks, OnPreferenceChangeListener,
53         OnPreferenceClickListener {
54 
55     // constant value that can be used to check return code from sub activity.
56     private static final int INSTALLED_APP_DETAILS = 1;
57 
58     private ApplicationsState mApplicationsState;
59     private ApplicationsState.Session mSession;
60     private PreferenceGroup mDomainAppList;
61     private SwitchPreference mWebAction;
62     private Preference mInstantAppAccountPreference;
63 
64     @Override
onCreate(Bundle icicle)65     public void onCreate(Bundle icicle) {
66         super.onCreate(icicle);
67         setAnimationAllowed(true);
68         mApplicationsState = ApplicationsState.getInstance(
69                 (Application) getContext().getApplicationContext());
70         mSession = mApplicationsState.newSession(this, getLifecycle());
71         setHasOptionsMenu(true);
72     }
73 
74     @Override
getPreferenceScreenResId()75     protected int getPreferenceScreenResId() {
76         return R.xml.manage_domain_url_settings;
77     }
78 
79     @Override
onViewCreated(View view, Bundle savedInstanceState)80     public void onViewCreated(View view, Bundle savedInstanceState) {
81         super.onViewCreated(view, savedInstanceState);
82     }
83 
84     @Override
onRunningStateChanged(boolean running)85     public void onRunningStateChanged(boolean running) {
86     }
87 
88     @Override
onPackageListChanged()89     public void onPackageListChanged() {
90     }
91 
92     @Override
onRebuildComplete(ArrayList<AppEntry> apps)93     public void onRebuildComplete(ArrayList<AppEntry> apps) {
94         if (getContext() == null) {
95             return;
96         }
97 
98         final boolean disableWebActions = Global.getInt(getContext().getContentResolver(),
99                 Global.ENABLE_EPHEMERAL_FEATURE, 1) == 0;
100         if (disableWebActions) {
101             mDomainAppList = getPreferenceScreen();
102         } else {
103             final PreferenceGroup preferenceScreen = getPreferenceScreen();
104             if (preferenceScreen.getPreferenceCount() == 0) {
105                 // add preferences
106                 final PreferenceCategory webActionCategory =
107                         new PreferenceCategory(getPrefContext());
108                 webActionCategory.setTitle(R.string.web_action_section_title);
109                 preferenceScreen.addPreference(webActionCategory);
110 
111                 // toggle to enable / disable Web Actions [aka Instant Apps]
112                 mWebAction = new SwitchPreference(getPrefContext());
113                 mWebAction.setTitle(R.string.web_action_enable_title);
114                 mWebAction.setSummary(R.string.web_action_enable_summary);
115                 mWebAction.setChecked(Settings.Secure.getInt(getContentResolver(),
116                         Settings.Secure.INSTANT_APPS_ENABLED, 1) != 0);
117                 mWebAction.setOnPreferenceChangeListener(this);
118                 webActionCategory.addPreference(mWebAction);
119 
120                 // Determine whether we should show the instant apps account chooser setting
121                 ComponentName instantAppSettingsComponent = getActivity().getPackageManager()
122                         .getInstantAppResolverSettingsComponent();
123                 Intent instantAppSettingsIntent = null;
124                 if (instantAppSettingsComponent != null) {
125                     instantAppSettingsIntent =
126                             new Intent().setComponent(instantAppSettingsComponent);
127                 }
128                 if (instantAppSettingsIntent != null) {
129                     final Intent launchIntent = instantAppSettingsIntent;
130                     // TODO: Make this button actually launch the account chooser.
131                     mInstantAppAccountPreference = new Preference(getPrefContext());
132                     mInstantAppAccountPreference.setTitle(R.string.instant_apps_settings);
133                     mInstantAppAccountPreference.setOnPreferenceClickListener(pref -> {
134                         startActivity(launchIntent);
135                         return true;
136                     });
137                     webActionCategory.addPreference(mInstantAppAccountPreference);
138                 }
139 
140                 // list to manage link handling per app
141                 mDomainAppList = new PreferenceCategory(getPrefContext());
142                 mDomainAppList.setTitle(R.string.domain_url_section_title);
143                 preferenceScreen.addPreference(mDomainAppList);
144             }
145         }
146         rebuildAppList(mDomainAppList, apps);
147     }
148 
149     @Override
onPreferenceChange(Preference preference, Object newValue)150     public boolean onPreferenceChange(Preference preference, Object newValue) {
151         if (preference == mWebAction) {
152             boolean checked = (boolean) newValue;
153             Settings.Secure.putInt(
154                     getContentResolver(),
155                     Settings.Secure.INSTANT_APPS_ENABLED, checked ? 1 : 0);
156             return true;
157         }
158         return false;
159     }
160 
rebuild()161     private void rebuild() {
162         final ArrayList<AppEntry> apps = mSession.rebuild(
163                 ApplicationsState.FILTER_WITH_DOMAIN_URLS, ApplicationsState.ALPHA_COMPARATOR);
164         if (apps != null) {
165             onRebuildComplete(apps);
166         }
167     }
168 
rebuildAppList(PreferenceGroup group, ArrayList<AppEntry> apps)169     private void rebuildAppList(PreferenceGroup group, ArrayList<AppEntry> apps) {
170         cacheRemoveAllPrefs(group);
171         final int N = apps.size();
172         for (int i = 0; i < N; i++) {
173             AppEntry entry = apps.get(i);
174             String key = entry.info.packageName + "|" + entry.info.uid;
175             DomainAppPreference preference = (DomainAppPreference) getCachedPreference(key);
176             if (preference == null) {
177                 preference = new DomainAppPreference(getPrefContext(), mApplicationsState, entry);
178                 preference.setKey(key);
179                 preference.setOnPreferenceClickListener(this);
180                 group.addPreference(preference);
181             } else {
182                 preference.reuse();
183             }
184             preference.setOrder(i);
185         }
186         removeCachedPrefs(group);
187     }
188 
189     @Override
onPackageIconChanged()190     public void onPackageIconChanged() {
191     }
192 
193     @Override
onPackageSizeChanged(String packageName)194     public void onPackageSizeChanged(String packageName) {
195     }
196 
197     @Override
onAllSizesComputed()198     public void onAllSizesComputed() {
199     }
200 
201     @Override
onLauncherInfoChanged()202     public void onLauncherInfoChanged() {
203     }
204 
205     @Override
onLoadEntriesCompleted()206     public void onLoadEntriesCompleted() {
207         rebuild();
208     }
209 
210     @Override
getMetricsCategory()211     public int getMetricsCategory() {
212         return MetricsEvent.MANAGE_DOMAIN_URLS;
213     }
214 
215     @Override
onPreferenceClick(Preference preference)216     public boolean onPreferenceClick(Preference preference) {
217         if (preference.getClass() == DomainAppPreference.class) {
218             ApplicationsState.AppEntry entry = ((DomainAppPreference) preference).mEntry;
219             AppInfoBase.startAppInfoFragment(AppLaunchSettings.class, R.string.auto_launch_label,
220                     entry.info.packageName, entry.info.uid, this,
221                     INSTALLED_APP_DETAILS, getMetricsCategory());
222             return true;
223         }
224         return false;
225     }
226 
227     @VisibleForTesting
228     static class DomainAppPreference extends AppPreference {
229         private final AppEntry mEntry;
230         private final PackageManager mPm;
231         private final ApplicationsState mApplicationsState;
232 
DomainAppPreference(final Context context, ApplicationsState applicationsState, AppEntry entry)233         public DomainAppPreference(final Context context, ApplicationsState applicationsState,
234                 AppEntry entry) {
235             super(context);
236             mApplicationsState = applicationsState;
237             mPm = context.getPackageManager();
238             mEntry = entry;
239             mEntry.ensureLabel(getContext());
240             setState();
241             if (mEntry.icon != null) {
242                 setIcon(mEntry.icon);
243             }
244         }
245 
setState()246         private void setState() {
247             setTitle(mEntry.label);
248             setSummary(getDomainsSummary(mEntry.info.packageName));
249         }
250 
reuse()251         public void reuse() {
252             setState();
253             notifyChanged();
254         }
255 
256         @Override
onBindViewHolder(PreferenceViewHolder holder)257         public void onBindViewHolder(PreferenceViewHolder holder) {
258             if (mEntry.icon == null) {
259                 holder.itemView.post(new Runnable() {
260                     @Override
261                     public void run() {
262                         // Ensure we have an icon before binding.
263                         mApplicationsState.ensureIcon(mEntry);
264                         // This might trigger us to bind again, but it gives an easy way to only
265                         // load the icon once its needed, so its probably worth it.
266                         setIcon(mEntry.icon);
267                     }
268                 });
269             }
270             super.onBindViewHolder(holder);
271         }
272 
getDomainsSummary(String packageName)273         private CharSequence getDomainsSummary(String packageName) {
274             // If the user has explicitly said "no" for this package, that's the
275             // string we should show.
276             int domainStatus =
277                     mPm.getIntentVerificationStatusAsUser(packageName, UserHandle.myUserId());
278             if (domainStatus == PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER) {
279                 return getContext().getString(R.string.domain_urls_summary_none);
280             }
281             // Otherwise, ask package manager for the domains for this package,
282             // and show the first one (or none if there aren't any).
283             ArraySet<String> result = Utils.getHandledDomains(mPm, packageName);
284             if (result.size() == 0) {
285                 return getContext().getString(R.string.domain_urls_summary_none);
286             } else if (result.size() == 1) {
287                 return getContext().getString(R.string.domain_urls_summary_one, result.valueAt(0));
288             } else {
289                 return getContext().getString(R.string.domain_urls_summary_some, result.valueAt(0));
290             }
291         }
292     }
293 }
294