AppLaunchSettings.java revision 49b6103b56d777cb41f280e0dc636f738f6ba56d
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.app.AlertDialog;
20import android.content.IntentFilter;
21import android.content.pm.ApplicationInfo;
22import android.content.pm.IntentFilterVerificationInfo;
23import android.content.pm.PackageManager;
24import android.os.Bundle;
25import android.os.UserHandle;
26import android.preference.Preference;
27import android.preference.Preference.OnPreferenceChangeListener;
28import android.util.ArraySet;
29import android.util.Log;
30import android.view.View;
31import android.view.View.OnClickListener;
32
33import com.android.internal.logging.MetricsLogger;
34import com.android.settings.DropDownPreference;
35import com.android.settings.R;
36import com.android.settings.Utils;
37
38import java.util.List;
39
40import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS;
41import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK;
42import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER;
43import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
44
45public class AppLaunchSettings extends AppInfoWithHeader implements OnClickListener,
46        Preference.OnPreferenceChangeListener {
47    private static final String TAG = "AppLaunchSettings";
48
49    private static final String KEY_APP_LINK_STATE = "app_link_state";
50    private static final String KEY_SUPPORTED_DOMAIN_URLS = "app_launch_supported_domain_urls";
51    private static final String KEY_CLEAR_DEFAULTS = "app_launch_clear_defaults";
52
53    private PackageManager mPm;
54
55    private boolean mHasDomainUrls;
56    private DropDownPreference mAppLinkState;
57    private AppDomainsPreference mAppDomainUrls;
58    private ClearDefaultsPreference mClearDefaultsPreference;
59
60    @Override
61    public void onCreate(Bundle savedInstanceState) {
62        super.onCreate(savedInstanceState);
63
64        addPreferencesFromResource(R.xml.installed_app_launch_settings);
65
66        mPm = getActivity().getPackageManager();
67
68        mHasDomainUrls =
69                (mAppEntry.info.privateFlags & ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS) != 0;
70        List<IntentFilterVerificationInfo> iviList = mPm.getIntentFilterVerifications(mPackageName);
71
72        List<IntentFilter> filters = mPm.getAllIntentFilters(mPackageName);
73
74        mAppDomainUrls = (AppDomainsPreference) findPreference(KEY_SUPPORTED_DOMAIN_URLS);
75        CharSequence[] entries = getEntries(mPackageName, iviList, filters);
76        mAppDomainUrls.setTitles(entries);
77        mAppDomainUrls.setValues(new int[entries.length]);
78
79        mClearDefaultsPreference = (ClearDefaultsPreference) findPreference(KEY_CLEAR_DEFAULTS);
80
81        buildStateDropDown();
82    }
83
84    private void buildStateDropDown() {
85        mAppLinkState = (DropDownPreference) findPreference(KEY_APP_LINK_STATE);
86
87        // Designed order of states in the dropdown:
88        //
89        // * always
90        // * ask
91        // * never
92        mAppLinkState.setEntries(new CharSequence[] {
93                getString(R.string.app_link_open_always),
94                getString(R.string.app_link_open_ask),
95                getString(R.string.app_link_open_never),
96        });
97        mAppLinkState.setEntryValues(new CharSequence[] {
98                Integer.toString(INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS),
99                Integer.toString(INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK),
100                Integer.toString(INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER),
101        });
102
103        mAppLinkState.setEnabled(mHasDomainUrls);
104        if (mHasDomainUrls) {
105            // Present 'undefined' as 'ask' because the OS treats them identically for
106            // purposes of the UI (and does the right thing around pending domain
107            // verifications that might arrive after the user chooses 'ask' in this UI).
108            final int state = mPm.getIntentVerificationStatus(mPackageName, UserHandle.myUserId());
109            mAppLinkState.setValue(
110                    Integer.toString((state == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED)
111                        ? INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK
112                        : state));
113
114            // Set the callback only after setting the initial selected item
115            mAppLinkState.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
116                @Override
117                public boolean onPreferenceChange(Preference preference, Object newValue) {
118                    return updateAppLinkState(Integer.parseInt((String) newValue));
119                }
120            });
121        }
122    }
123
124    private boolean updateAppLinkState(final int newState) {
125        final int userId = UserHandle.myUserId();
126        final int priorState = mPm.getIntentVerificationStatus(mPackageName, userId);
127
128        if (priorState == newState) {
129            return false;
130        }
131
132        boolean success = mPm.updateIntentVerificationStatus(mPackageName, newState, userId);
133        if (success) {
134            // Read back the state to see if the change worked
135            final int updatedState = mPm.getIntentVerificationStatus(mPackageName, userId);
136            success = (newState == updatedState);
137        } else {
138            Log.e(TAG, "Couldn't update intent verification status!");
139        }
140        return success;
141    }
142
143    private CharSequence[] getEntries(String packageName, List<IntentFilterVerificationInfo> iviList,
144            List<IntentFilter> filters) {
145        ArraySet<String> result = Utils.getHandledDomains(mPm, packageName);
146        return result.toArray(new CharSequence[result.size()]);
147    }
148
149    @Override
150    protected boolean refreshUi() {
151        mClearDefaultsPreference.setPackageName(mPackageName);
152        mClearDefaultsPreference.setAppEntry(mAppEntry);
153        return true;
154    }
155
156    @Override
157    protected AlertDialog createDialog(int id, int errorCode) {
158        // No dialogs for preferred launch settings.
159        return null;
160    }
161
162    @Override
163    public void onClick(View v) {
164        // Nothing to do
165    }
166
167    @Override
168    public boolean onPreferenceChange(Preference preference, Object newValue) {
169        // actual updates are handled by the app link dropdown callback
170        return true;
171    }
172
173    @Override
174    protected int getMetricsCategory() {
175        return MetricsLogger.APPLICATIONS_APP_LAUNCH;
176    }
177}
178