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.content.ComponentName;
21 import android.content.Context;
22 import android.content.Intent;
23 import android.util.LayoutDirection;
24 import android.util.Log;
25 
26 import androidx.window.embedding.ActivityFilter;
27 import androidx.window.embedding.ActivityRule;
28 import androidx.window.embedding.SplitController;
29 import androidx.window.embedding.SplitPairFilter;
30 import androidx.window.embedding.SplitPairRule;
31 import androidx.window.embedding.SplitPlaceholderRule;
32 import androidx.window.embedding.SplitRule;
33 
34 import com.android.settings.Settings;
35 import com.android.settings.SubSettings;
36 import com.android.settings.biometrics.fingerprint.FingerprintEnrollEnrolling;
37 import com.android.settings.biometrics.fingerprint.FingerprintEnrollIntroduction;
38 import com.android.settings.homepage.DeepLinkHomepageActivity;
39 import com.android.settings.homepage.SettingsHomepageActivity;
40 import com.android.settings.homepage.SliceDeepLinkHomepageActivity;
41 
42 import java.util.HashSet;
43 import java.util.Set;
44 
45 /** A class to initialize split rules for activity embedding. */
46 public class ActivityEmbeddingRulesController {
47 
48     private static final String TAG = "ActivityEmbeddingCtrl";
49     private final Context mContext;
50     private final SplitController mSplitController;
51 
ActivityEmbeddingRulesController(Context context)52     public ActivityEmbeddingRulesController(Context context) {
53         mContext = context;
54         mSplitController = SplitController.getInstance();
55     }
56 
57     /**
58      * Set up embedding rules to place activities to the right pane.
59      */
initRules()60     public void initRules() {
61         if (!ActivityEmbeddingUtils.isEmbeddingActivityEnabled(mContext)) {
62             Log.d(TAG, "Not support this feature now");
63             return;
64         }
65 
66         mSplitController.clearRegisteredRules();
67 
68         // Set a placeholder for home page.
69         registerHomepagePlaceholderRule();
70 
71         registerAlwaysExpandRule();
72     }
73 
74     /** Register a SplitPairRule for 2-pane. */
registerTwoPanePairRule(Context context, ComponentName primaryComponent, ComponentName secondaryComponent, String secondaryIntentAction, int finishPrimaryWithSecondary, int finishSecondaryWithPrimary, boolean clearTop)75     public static void registerTwoPanePairRule(Context context,
76             ComponentName primaryComponent,
77             ComponentName secondaryComponent,
78             String secondaryIntentAction,
79             int finishPrimaryWithSecondary,
80             int finishSecondaryWithPrimary,
81             boolean clearTop) {
82         if (!ActivityEmbeddingUtils.isEmbeddingActivityEnabled(context)) {
83             return;
84         }
85         final Set<SplitPairFilter> filters = new HashSet<>();
86         filters.add(new SplitPairFilter(primaryComponent, secondaryComponent,
87                 secondaryIntentAction));
88 
89         SplitController.getInstance().registerRule(new SplitPairRule(filters,
90                 finishPrimaryWithSecondary,
91                 finishSecondaryWithPrimary,
92                 clearTop,
93                 ActivityEmbeddingUtils.getMinCurrentScreenSplitWidthPx(context),
94                 ActivityEmbeddingUtils.getMinSmallestScreenSplitWidthPx(context),
95                 ActivityEmbeddingUtils.SPLIT_RATIO,
96                 LayoutDirection.LOCALE));
97     }
98 
99     /**
100      * Register a new SplitPairRule for Settings home. Because homepage is able to be opened by
101      * {@link Settings} or {@link SettingsHomepageActivity} or
102      * {@link SliceDeepLinkHomepageActivity}, we register split rule for above cases.
103      */
registerTwoPanePairRuleForSettingsHome(Context context, ComponentName secondaryComponent, String secondaryIntentAction, boolean finishPrimaryWithSecondary, boolean finishSecondaryWithPrimary, boolean clearTop)104     public static void registerTwoPanePairRuleForSettingsHome(Context context,
105             ComponentName secondaryComponent,
106             String secondaryIntentAction,
107             boolean finishPrimaryWithSecondary,
108             boolean finishSecondaryWithPrimary,
109             boolean clearTop) {
110         if (!ActivityEmbeddingUtils.isEmbeddingActivityEnabled(context)) {
111             return;
112         }
113 
114         registerTwoPanePairRule(
115                 context,
116                 new ComponentName(context, Settings.class),
117                 secondaryComponent,
118                 secondaryIntentAction,
119                 finishPrimaryWithSecondary ? SplitRule.FINISH_ADJACENT : SplitRule.FINISH_NEVER,
120                 finishSecondaryWithPrimary ? SplitRule.FINISH_ADJACENT : SplitRule.FINISH_NEVER,
121                 clearTop);
122 
123         registerTwoPanePairRule(
124                 context,
125                 new ComponentName(context, SettingsHomepageActivity.class),
126                 secondaryComponent,
127                 secondaryIntentAction,
128                 finishPrimaryWithSecondary ? SplitRule.FINISH_ADJACENT : SplitRule.FINISH_NEVER,
129                 finishSecondaryWithPrimary ? SplitRule.FINISH_ADJACENT : SplitRule.FINISH_NEVER,
130                 clearTop);
131 
132         // We should finish HomePageActivity altogether even if it shows in single pane for all deep
133         // link cases.
134         registerTwoPanePairRule(
135                 context,
136                 new ComponentName(context, DeepLinkHomepageActivity.class),
137                 secondaryComponent,
138                 secondaryIntentAction,
139                 finishPrimaryWithSecondary ? SplitRule.FINISH_ALWAYS : SplitRule.FINISH_NEVER,
140                 finishSecondaryWithPrimary ? SplitRule.FINISH_ALWAYS : SplitRule.FINISH_NEVER,
141                 clearTop);
142 
143         registerTwoPanePairRule(
144                 context,
145                 new ComponentName(context, SliceDeepLinkHomepageActivity.class),
146                 secondaryComponent,
147                 secondaryIntentAction,
148                 finishPrimaryWithSecondary ? SplitRule.FINISH_ALWAYS : SplitRule.FINISH_NEVER,
149                 finishSecondaryWithPrimary ? SplitRule.FINISH_ALWAYS : SplitRule.FINISH_NEVER,
150                 clearTop);
151     }
152 
153     /**
154      * Register a new SplitPairRule for Settings home.
155      */
registerTwoPanePairRuleForSettingsHome(Context context, ComponentName secondaryComponent, String secondaryIntentAction, boolean clearTop)156     public static void registerTwoPanePairRuleForSettingsHome(Context context,
157             ComponentName secondaryComponent,
158             String secondaryIntentAction,
159             boolean clearTop) {
160         if (!ActivityEmbeddingUtils.isEmbeddingActivityEnabled(context)) {
161             return;
162         }
163 
164         registerTwoPanePairRuleForSettingsHome(
165                 context,
166                 secondaryComponent,
167                 secondaryIntentAction,
168                 true /* finishPrimaryWithSecondary */,
169                 true /* finishSecondaryWithPrimary */,
170                 clearTop);
171     }
172 
173     /** Register a SplitPairRule for SubSettings if the device supports 2-pane. */
registerSubSettingsPairRule(Context context, boolean clearTop)174     public static void registerSubSettingsPairRule(Context context, boolean clearTop) {
175         if (!ActivityEmbeddingUtils.isEmbeddingActivityEnabled(context)) {
176             return;
177         }
178 
179         registerTwoPanePairRuleForSettingsHome(
180                 context,
181                 new ComponentName(context, SubSettings.class),
182                 null /* secondaryIntentAction */,
183                 clearTop);
184     }
185 
registerHomepagePlaceholderRule()186     private void registerHomepagePlaceholderRule() {
187         final Set<ActivityFilter> activityFilters = new HashSet<>();
188         addActivityFilter(activityFilters, SettingsHomepageActivity.class);
189         addActivityFilter(activityFilters, DeepLinkHomepageActivity.class);
190         addActivityFilter(activityFilters, SliceDeepLinkHomepageActivity.class);
191         addActivityFilter(activityFilters, Settings.class);
192 
193         final Intent intent = new Intent(mContext, Settings.NetworkDashboardActivity.class);
194         final SplitPlaceholderRule placeholderRule = new SplitPlaceholderRule(
195                 activityFilters,
196                 intent,
197                 true /* stickyPlaceholder */,
198                 SplitRule.FINISH_ADJACENT,
199                 ActivityEmbeddingUtils.getMinCurrentScreenSplitWidthPx(mContext),
200                 ActivityEmbeddingUtils.getMinSmallestScreenSplitWidthPx(mContext),
201                 ActivityEmbeddingUtils.SPLIT_RATIO,
202                 LayoutDirection.LOCALE);
203 
204         mSplitController.registerRule(placeholderRule);
205     }
206 
registerAlwaysExpandRule()207     private void registerAlwaysExpandRule() {
208         final Set<ActivityFilter> activityFilters = new HashSet<>();
209         addActivityFilter(activityFilters, FingerprintEnrollIntroduction.class);
210         addActivityFilter(activityFilters, FingerprintEnrollEnrolling.class);
211         mSplitController.registerRule(new ActivityRule(activityFilters, true /* alwaysExpand */));
212     }
213 
addActivityFilter(Set<ActivityFilter> activityFilters, Class<? extends Activity> activityClass)214     private void addActivityFilter(Set<ActivityFilter> activityFilters,
215             Class<? extends Activity> activityClass) {
216         activityFilters.add(new ActivityFilter(new ComponentName(mContext, activityClass),
217                 null /* intentAction */));
218     }
219 }
220