• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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 
17 package com.android.settings.activityembedding;
18 
19 import android.app.Activity;
20 import android.app.settings.SettingsEnums;
21 import android.content.ComponentName;
22 import android.content.Context;
23 import android.content.Intent;
24 import android.util.FeatureFlagUtils;
25 import android.util.Log;
26 
27 import androidx.window.embedding.ActivityFilter;
28 import androidx.window.embedding.ActivityRule;
29 import androidx.window.embedding.EmbeddingAspectRatio;
30 import androidx.window.embedding.RuleController;
31 import androidx.window.embedding.SplitAttributes;
32 import androidx.window.embedding.SplitPairFilter;
33 import androidx.window.embedding.SplitPairRule;
34 import androidx.window.embedding.SplitPlaceholderRule;
35 import androidx.window.embedding.SplitRule;
36 
37 import com.android.settings.Settings;
38 import com.android.settings.SettingsActivity;
39 import com.android.settings.SubSettings;
40 import com.android.settings.biometrics.face.FaceEnrollIntroduction;
41 import com.android.settings.biometrics.face.FaceEnrollIntroductionInternal;
42 import com.android.settings.biometrics.fingerprint.FingerprintEnrollEnrolling;
43 import com.android.settings.biometrics.fingerprint.FingerprintEnrollIntroduction;
44 import com.android.settings.biometrics.fingerprint.FingerprintEnrollIntroductionInternal;
45 import com.android.settings.biometrics2.ui.view.FingerprintEnrollmentActivity;
46 import com.android.settings.core.FeatureFlags;
47 import com.android.settings.homepage.DeepLinkHomepageActivity;
48 import com.android.settings.homepage.DeepLinkHomepageActivityInternal;
49 import com.android.settings.homepage.SettingsHomepageActivity;
50 import com.android.settings.overlay.FeatureFactory;
51 import com.android.settings.password.ChooseLockPattern;
52 import com.android.settingslib.users.AvatarPickerActivity;
53 
54 import java.util.Collection;
55 import java.util.HashSet;
56 import java.util.Set;
57 
58 /** A class to initialize split rules for activity embedding. */
59 public class ActivityEmbeddingRulesController {
60 
61     private static final String TAG = "ActivityEmbeddingCtrl";
62     private static final ComponentName COMPONENT_NAME_WILDCARD = new ComponentName(
63             "*" /* pkg */, "*" /* cls */);
64     private final Context mContext;
65     private final RuleController mRuleController;
66 
ActivityEmbeddingRulesController(Context context)67     public ActivityEmbeddingRulesController(Context context) {
68         mContext = context;
69         mRuleController = RuleController.getInstance(context);
70     }
71 
72     /**
73      * Set up embedding rules to place activities to the right pane.
74      */
initRules()75     public void initRules() {
76         if (!ActivityEmbeddingUtils.isEmbeddingActivityEnabled(mContext)) {
77             Log.d(TAG, "Not support this feature now");
78             return;
79         }
80 
81         mRuleController.clearRules();
82 
83         // Set a placeholder for home page.
84         registerHomepagePlaceholderRule();
85 
86         registerAlwaysExpandRule();
87     }
88 
89     /** Register a SplitPairRule for 2-pane. */
registerTwoPanePairRule(Context context, ComponentName primaryComponent, ComponentName secondaryComponent, String secondaryIntentAction, SplitRule.FinishBehavior finishPrimaryWithSecondary, SplitRule.FinishBehavior finishSecondaryWithPrimary, boolean clearTop)90     public static void registerTwoPanePairRule(Context context,
91             ComponentName primaryComponent,
92             ComponentName secondaryComponent,
93             String secondaryIntentAction,
94             SplitRule.FinishBehavior finishPrimaryWithSecondary,
95             SplitRule.FinishBehavior finishSecondaryWithPrimary,
96             boolean clearTop) {
97         if (!ActivityEmbeddingUtils.isEmbeddingActivityEnabled(context)) {
98             return;
99         }
100         final Set<SplitPairFilter> filters = new HashSet<>();
101         filters.add(new SplitPairFilter(primaryComponent, secondaryComponent,
102                 secondaryIntentAction));
103 
104         SplitAttributes attributes = new SplitAttributes.Builder()
105                 .setSplitType(SplitAttributes.SplitType.ratio(
106                         ActivityEmbeddingUtils.getSplitRatio(context)))
107                 .setLayoutDirection(SplitAttributes.LayoutDirection.LOCALE)
108                 .build();
109         SplitPairRule splitPairRule = new SplitPairRule.Builder(filters)
110                 .setFinishPrimaryWithSecondary(finishPrimaryWithSecondary)
111                 .setFinishSecondaryWithPrimary(finishSecondaryWithPrimary)
112                 .setClearTop(clearTop)
113                 .setMinWidthDp(ActivityEmbeddingUtils.getMinCurrentScreenSplitWidthDp())
114                 .setMinSmallestWidthDp(ActivityEmbeddingUtils.getMinSmallestScreenSplitWidthDp())
115                 .setMaxAspectRatioInPortrait(EmbeddingAspectRatio.ALWAYS_ALLOW)
116                 .setDefaultSplitAttributes(attributes)
117                 .build();
118         RuleController.getInstance(context).addRule(splitPairRule);
119     }
120 
121     /**
122      * Registers a {@link SplitPairRule} for all classes that Settings homepage can be invoked from.
123      */
registerTwoPanePairRuleForSettingsHome(Context context, ComponentName secondaryComponent, String secondaryIntentAction, boolean finishPrimaryWithSecondary, boolean finishSecondaryWithPrimary, boolean clearTop)124     public static void registerTwoPanePairRuleForSettingsHome(Context context,
125             ComponentName secondaryComponent,
126             String secondaryIntentAction,
127             boolean finishPrimaryWithSecondary,
128             boolean finishSecondaryWithPrimary,
129             boolean clearTop) {
130         if (!ActivityEmbeddingUtils.isEmbeddingActivityEnabled(context)) {
131             return;
132         }
133 
134         registerTwoPanePairRule(
135                 context,
136                 new ComponentName(context, Settings.class),
137                 secondaryComponent,
138                 secondaryIntentAction,
139                 finishPrimaryWithSecondary ? SplitRule.FinishBehavior.ADJACENT
140                         : SplitRule.FinishBehavior.NEVER,
141                 finishSecondaryWithPrimary ? SplitRule.FinishBehavior.ADJACENT
142                         : SplitRule.FinishBehavior.NEVER,
143                 clearTop);
144 
145         registerTwoPanePairRule(
146                 context,
147                 new ComponentName(context, SettingsHomepageActivity.class),
148                 secondaryComponent,
149                 secondaryIntentAction,
150                 finishPrimaryWithSecondary ? SplitRule.FinishBehavior.ADJACENT
151                         : SplitRule.FinishBehavior.NEVER,
152                 finishSecondaryWithPrimary ? SplitRule.FinishBehavior.ADJACENT
153                         : SplitRule.FinishBehavior.NEVER,
154                 clearTop);
155 
156         // We should finish HomePageActivity altogether even if it shows in single pane for all deep
157         // link cases.
158         registerTwoPanePairRule(
159                 context,
160                 new ComponentName(context, DeepLinkHomepageActivity.class),
161                 secondaryComponent,
162                 secondaryIntentAction,
163                 finishPrimaryWithSecondary ? SplitRule.FinishBehavior.ALWAYS
164                         : SplitRule.FinishBehavior.NEVER,
165                 finishSecondaryWithPrimary ? SplitRule.FinishBehavior.ALWAYS
166                         : SplitRule.FinishBehavior.NEVER,
167                 clearTop);
168 
169         registerTwoPanePairRule(
170                 context,
171                 new ComponentName(context, DeepLinkHomepageActivityInternal.class),
172                 secondaryComponent,
173                 secondaryIntentAction,
174                 finishPrimaryWithSecondary ? SplitRule.FinishBehavior.ALWAYS
175                         : SplitRule.FinishBehavior.NEVER,
176                 finishSecondaryWithPrimary ? SplitRule.FinishBehavior.ALWAYS
177                         : SplitRule.FinishBehavior.NEVER,
178                 clearTop);
179     }
180 
181     /**
182      * Register a new SplitPairRule for Settings home.
183      */
registerTwoPanePairRuleForSettingsHome(Context context, ComponentName secondaryComponent, String secondaryIntentAction, boolean clearTop)184     public static void registerTwoPanePairRuleForSettingsHome(Context context,
185             ComponentName secondaryComponent,
186             String secondaryIntentAction,
187             boolean clearTop) {
188         if (!ActivityEmbeddingUtils.isEmbeddingActivityEnabled(context)) {
189             return;
190         }
191 
192         registerTwoPanePairRuleForSettingsHome(
193                 context,
194                 secondaryComponent,
195                 secondaryIntentAction,
196                 true /* finishPrimaryWithSecondary */,
197                 true /* finishSecondaryWithPrimary */,
198                 clearTop);
199     }
200 
201     /** Register a SplitPairRule for SubSettings if the device supports 2-pane. */
registerSubSettingsPairRule(Context context, boolean clearTop)202     public static void registerSubSettingsPairRule(Context context, boolean clearTop) {
203         if (!ActivityEmbeddingUtils.isEmbeddingActivityEnabled(context)) {
204             return;
205         }
206 
207         registerTwoPanePairRuleForSettingsHome(
208                 context,
209                 new ComponentName(context, SubSettings.class),
210                 null /* secondaryIntentAction */,
211                 clearTop);
212 
213         registerTwoPanePairRuleForSettingsHome(
214                 context,
215                 COMPONENT_NAME_WILDCARD,
216                 Intent.ACTION_SAFETY_CENTER,
217                 clearTop
218         );
219     }
220 
registerHomepagePlaceholderRule()221     private void registerHomepagePlaceholderRule() {
222         final Set<ActivityFilter> activityFilters = new HashSet<>();
223         addActivityFilter(activityFilters, SettingsHomepageActivity.class);
224         addActivityFilter(activityFilters, Settings.class);
225 
226         final Intent intent = new Intent(mContext, Settings.NetworkDashboardActivity.class);
227         intent.putExtra(SettingsActivity.EXTRA_IS_SECOND_LAYER_PAGE, true);
228         SplitAttributes attributes = new SplitAttributes.Builder()
229                 .setSplitType(SplitAttributes.SplitType.ratio(
230                         ActivityEmbeddingUtils.getSplitRatio(mContext)))
231                 .build();
232         final SplitPlaceholderRule placeholderRule = new SplitPlaceholderRule.Builder(
233                 activityFilters, intent)
234                 .setMinWidthDp(ActivityEmbeddingUtils.getMinCurrentScreenSplitWidthDp())
235                 .setMinSmallestWidthDp(ActivityEmbeddingUtils.getMinSmallestScreenSplitWidthDp())
236                 .setMaxAspectRatioInPortrait(EmbeddingAspectRatio.ALWAYS_ALLOW)
237                 .setSticky(false)
238                 .setFinishPrimaryWithPlaceholder(SplitRule.FinishBehavior.ADJACENT)
239                 .setDefaultSplitAttributes(attributes)
240                 .build();
241 
242         mRuleController.addRule(placeholderRule);
243     }
244 
registerAlwaysExpandRule()245     private void registerAlwaysExpandRule() {
246         final Set<ActivityFilter> activityFilters = new HashSet<>();
247         if (FeatureFlagUtils.isEnabled(mContext, FeatureFlags.SETTINGS_SEARCH_ALWAYS_EXPAND)) {
248             final Intent searchIntent = FeatureFactory.getFactory(mContext)
249                     .getSearchFeatureProvider()
250                     .buildSearchIntent(mContext, SettingsEnums.SETTINGS_HOMEPAGE);
251             addActivityFilter(activityFilters, searchIntent);
252         }
253         addActivityFilter(activityFilters, FingerprintEnrollmentActivity.class);
254         addActivityFilter(activityFilters, FingerprintEnrollIntroduction.class);
255         addActivityFilter(activityFilters, FingerprintEnrollIntroductionInternal.class);
256         addActivityFilter(activityFilters, FingerprintEnrollEnrolling.class);
257         addActivityFilter(activityFilters, FaceEnrollIntroductionInternal.class);
258         addActivityFilter(activityFilters, FaceEnrollIntroduction.class);
259         addActivityFilter(activityFilters, AvatarPickerActivity.class);
260         addActivityFilter(activityFilters, ChooseLockPattern.class);
261         ActivityRule activityRule = new ActivityRule.Builder(activityFilters).setAlwaysExpand(true)
262                 .build();
263         mRuleController.addRule(activityRule);
264     }
265 
addActivityFilter(Set<ActivityFilter> activityFilters, Intent intent)266     private static void addActivityFilter(Set<ActivityFilter> activityFilters, Intent intent) {
267         activityFilters.add(new ActivityFilter(COMPONENT_NAME_WILDCARD, intent.getAction()));
268     }
269 
addActivityFilter(Collection<ActivityFilter> activityFilters, Class<? extends Activity> activityClass)270     private void addActivityFilter(Collection<ActivityFilter> activityFilters,
271             Class<? extends Activity> activityClass) {
272         activityFilters.add(new ActivityFilter(new ComponentName(mContext, activityClass),
273                 null /* intentAction */));
274     }
275 }
276