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