1/*
2 * Copyright (C) 2018 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.core;
18
19import android.annotation.StringRes;
20import android.app.Fragment;
21import android.content.Context;
22import android.content.Intent;
23import android.os.Bundle;
24import android.os.UserHandle;
25import android.support.annotation.VisibleForTesting;
26import android.text.TextUtils;
27
28import com.android.settings.SettingsActivity;
29import com.android.settings.SubSettings;
30import com.android.settingslib.core.instrumentation.VisibilityLoggerMixin;
31
32public class SubSettingLauncher {
33
34    private final Context mContext;
35    private final LaunchRequest mLaunchRequest;
36    private boolean mLaunched;
37
38    public SubSettingLauncher(Context context) {
39        if (context == null) {
40            throw new IllegalArgumentException("Context must be non-null.");
41        }
42        mContext = context;
43        mLaunchRequest = new LaunchRequest();
44    }
45
46    public SubSettingLauncher setDestination(String fragmentName) {
47        mLaunchRequest.destinationName = fragmentName;
48        return this;
49    }
50
51    public SubSettingLauncher setTitle(@StringRes int titleResId) {
52        return setTitle(null /*titlePackageName*/, titleResId);
53    }
54
55    public SubSettingLauncher setTitle(String titlePackageName, @StringRes int titleResId) {
56        mLaunchRequest.titleResPackageName = titlePackageName;
57        mLaunchRequest.titleResId = titleResId;
58        mLaunchRequest.title = null;
59        return this;
60    }
61
62    public SubSettingLauncher setTitle(CharSequence title) {
63        mLaunchRequest.title = title;
64        return this;
65    }
66
67    public SubSettingLauncher setIsShortCut(boolean isShortCut) {
68        mLaunchRequest.isShortCut = isShortCut;
69        return this;
70    }
71
72    public SubSettingLauncher setArguments(Bundle arguments) {
73        mLaunchRequest.arguments = arguments;
74        return this;
75    }
76
77    public SubSettingLauncher setSourceMetricsCategory(int sourceMetricsCategory) {
78        mLaunchRequest.sourceMetricsCategory = sourceMetricsCategory;
79        return this;
80    }
81
82    public SubSettingLauncher setResultListener(Fragment listener, int resultRequestCode) {
83        mLaunchRequest.mRequestCode = resultRequestCode;
84        mLaunchRequest.mResultListener = listener;
85        return this;
86    }
87
88    public SubSettingLauncher addFlags(int flags) {
89        mLaunchRequest.flags |= flags;
90        return this;
91    }
92
93    public SubSettingLauncher setUserHandle(UserHandle userHandle) {
94        mLaunchRequest.userHandle = userHandle;
95        return this;
96    }
97
98    public void launch() {
99        if (mLaunched) {
100            throw new IllegalStateException(
101                    "This launcher has already been executed. Do not reuse");
102        }
103        mLaunched = true;
104
105        final Intent intent = toIntent();
106
107        boolean launchAsUser = mLaunchRequest.userHandle != null
108                && mLaunchRequest.userHandle.getIdentifier() != UserHandle.myUserId();
109        boolean launchForResult = mLaunchRequest.mResultListener != null;
110        if (launchAsUser && launchForResult) {
111            launchForResultAsUser(intent, mLaunchRequest.userHandle, mLaunchRequest.mResultListener,
112                    mLaunchRequest.mRequestCode);
113        } else if (launchAsUser && !launchForResult) {
114            launchAsUser(intent, mLaunchRequest.userHandle);
115        } else if (!launchAsUser && launchForResult) {
116            launchForResult(mLaunchRequest.mResultListener, intent, mLaunchRequest.mRequestCode);
117        } else {
118            launch(intent);
119        }
120    }
121
122    public Intent toIntent() {
123        final Intent intent = new Intent(Intent.ACTION_MAIN);
124        intent.setClass(mContext, SubSettings.class);
125        if (TextUtils.isEmpty(mLaunchRequest.destinationName)) {
126            throw new IllegalArgumentException("Destination fragment must be set");
127        }
128        intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT, mLaunchRequest.destinationName);
129
130        if (mLaunchRequest.sourceMetricsCategory < 0) {
131            throw new IllegalArgumentException("Source metrics category must be set");
132        }
133        intent.putExtra(VisibilityLoggerMixin.EXTRA_SOURCE_METRICS_CATEGORY,
134                mLaunchRequest.sourceMetricsCategory);
135
136        intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS, mLaunchRequest.arguments);
137        intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_TITLE_RES_PACKAGE_NAME,
138                mLaunchRequest.titleResPackageName);
139        intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_TITLE_RESID,
140                mLaunchRequest.titleResId);
141        intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_TITLE, mLaunchRequest.title);
142        intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_AS_SHORTCUT,
143                mLaunchRequest.isShortCut);
144        intent.addFlags(mLaunchRequest.flags);
145        return intent;
146    }
147
148    @VisibleForTesting
149    void launch(Intent intent) {
150        mContext.startActivity(intent);
151    }
152
153    @VisibleForTesting
154    void launchAsUser(Intent intent, UserHandle userHandle) {
155        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
156        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
157        mContext.startActivityAsUser(intent, userHandle);
158    }
159
160    @VisibleForTesting
161    void launchForResultAsUser(Intent intent, UserHandle userHandle,
162            Fragment resultListener, int requestCode) {
163        resultListener.getActivity().startActivityForResultAsUser(intent, requestCode, userHandle);
164    }
165
166    private void launchForResult(Fragment listener, Intent intent, int requestCode) {
167        listener.startActivityForResult(intent, requestCode);
168    }
169
170    /**
171     * Simple container that has information about how to launch a subsetting.
172     */
173    static class LaunchRequest {
174        String destinationName;
175        int titleResId;
176        String titleResPackageName;
177        CharSequence title;
178        boolean isShortCut;
179        int sourceMetricsCategory = -100;
180        int flags;
181        Fragment mResultListener;
182        int mRequestCode;
183        UserHandle userHandle;
184        Bundle arguments;
185    }
186}
187