Loading AndroidManifest.xml +13 −0 Original line number Diff line number Diff line Loading @@ -107,6 +107,8 @@ <uses-permission android:name="android.permission.READ_DREAM_STATE" /> <uses-permission android:name="android.permission.READ_DREAM_SUPPRESSION" /> <uses-permission android:name="android.permission.MANAGE_APP_HIBERNATION" /> <uses-permission android:name="android.permission.LAUNCH_TWO_PANE_SETTINGS_DEEP_LINK" /> <uses-permission android:name="android.permission.ALLOW_PLACE_IN_TWO_PANE_SETTINGS" /> <application android:name=".SettingsApplication" Loading Loading @@ -172,6 +174,17 @@ <meta-data android:name="android.app.shortcuts" android:resource="@xml/shortcuts"/> </activity-alias> <!-- Alias for SettingsHomepageActivity which works for deep link page in 2-panel. --> <activity-alias android:name="DeepLinkHomepageActivity" android:label="@string/settings_label_launcher" android:exported="true" android:targetActivity=".homepage.SettingsHomepageActivity"> <intent-filter> <action android:name="android.settings.SETTINGS_LARGE_SCREEN_DEEP_LINK" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity-alias> <receiver android:name=".SettingsInitialize" android:exported="true"> <intent-filter> Loading src/com/android/settings/SettingsActivity.java +23 −0 Original line number Diff line number Diff line Loading @@ -58,6 +58,8 @@ import com.android.settings.core.SettingsBaseActivity; import com.android.settings.core.SubSettingLauncher; import com.android.settings.core.gateway.SettingsGateway; import com.android.settings.dashboard.DashboardFeatureProvider; import com.android.settings.activityembedding.ActivityEmbeddingUtils; import com.android.settings.homepage.SettingsHomepageActivity; import com.android.settings.homepage.TopLevelSettings; import com.android.settings.overlay.FeatureFactory; import com.android.settings.wfd.WifiDisplaySettings; Loading Loading @@ -240,7 +242,22 @@ public class SettingsActivity extends SettingsBaseActivity // Should happen before any call to getIntent() getMetaData(); // If it's a deep link intent, start the Activity from SettingsHomepageActivity for 2-pane. final Intent intent = getIntent(); final boolean isFromSettingsHomepage = intent.getBooleanExtra( SettingsHomepageActivity.EXTRA_IS_FROM_SETTINGS_HOMEPAGE, /* defaultValue */ false); if (ActivityEmbeddingUtils.isEmbeddingActivityEnabled(this) && !isFromSettingsHomepage && isOnlyOneActivityInActivityStack()) { final Intent trampolineIntent = new Intent(android.provider.Settings.ACTION_SETTINGS_LARGE_SCREEN_DEEP_LINK); trampolineIntent.putExtra( android.provider.Settings.EXTRA_SETTINGS_LARGE_SCREEN_DEEP_LINK_INTENT_URI, intent.toUri(Intent.URI_INTENT_SCHEME)); startActivity(trampolineIntent); finish(); return; } if (intent.hasExtra(EXTRA_UI_OPTIONS)) { getWindow().setUiOptions(intent.getIntExtra(EXTRA_UI_OPTIONS, 0)); } Loading Loading @@ -347,6 +364,12 @@ public class SettingsActivity extends SettingsBaseActivity } } private boolean isOnlyOneActivityInActivityStack() { final ActivityManager activityManager = getSystemService(ActivityManager.class); List<ActivityManager.RunningTaskInfo> taskList = activityManager.getRunningTasks(2); return taskList.get(0).numActivities == 1; } /** Returns the initial fragment name that the activity will launch. */ @VisibleForTesting public String getInitialFragmentName(Intent intent) { Loading src/com/android/settings/activityembedding/ActivityEmbeddingRulesController.java +26 −24 Original line number Diff line number Diff line Loading @@ -60,12 +60,34 @@ public class ActivityEmbeddingRulesController { mSplitController.clearRegisteredRules(); // Set a placeholder for home page. mSplitController.registerRule(getHomepagePlaceholderRule()); registerHomepagePlaceholderRule(); // Set subsettings rule. mSplitController.registerRule(getSubSettingsPairRule()); registerTwoPanePairRule(mContext, getComponentName(Settings.class), getComponentName(SubSettings.class), true /* finishPrimaryWithSecondary */, true /* finishSecondaryWithPrimary */); } private SplitPlaceholderRule getHomepagePlaceholderRule() { /** Register a SplitPairRule for 2-pane. */ public static void registerTwoPanePairRule(Context context, ComponentName primary, ComponentName secondary, boolean finishPrimaryWithSecondary, boolean finishSecondaryWithPrimary) { final Set<SplitPairFilter> filters = new HashSet<>(); filters.add(new SplitPairFilter(primary, secondary, null /* secondaryActivityIntentAction */, null /* secondaryActivityIntentCategory */)); new SplitController(context).registerRule(new SplitPairRule(filters, finishPrimaryWithSecondary, finishSecondaryWithPrimary, true /* clearTop */, ActivityEmbeddingUtils.getMinCurrentScreenSplitWidthPx(context), ActivityEmbeddingUtils.getMinSmallestScreenSplitWidthPx(context), ActivityEmbeddingUtils.SPLIT_RATIO, LayoutDirection.LOCALE)); } private void registerHomepagePlaceholderRule() { final Set<ActivityFilter> activityFilters = new HashSet<>(); activityFilters.add(new ActivityFilter(getComponentName(Settings.class))); final Intent intent = new Intent(); Loading @@ -78,27 +100,7 @@ public class ActivityEmbeddingRulesController { ActivityEmbeddingUtils.SPLIT_RATIO, LayoutDirection.LOCALE); return placeholderRule; } private SplitPairRule getSubSettingsPairRule() { final Set<SplitPairFilter> pairFilters = new HashSet<>(); pairFilters.add(new SplitPairFilter( getComponentName(Settings.class), getComponentName(SubSettings.class), null /* secondaryActivityIntentAction */, null /* secondaryActivityIntentCategory */)); final SplitPairRule rule = new SplitPairRule( pairFilters, true /* finishPrimaryWithSecondary */, true /* finishSecondaryWithPrimary */, true /* clearTop */, ActivityEmbeddingUtils.getMinCurrentScreenSplitWidthPx(mContext), ActivityEmbeddingUtils.getMinSmallestScreenSplitWidthPx(mContext), ActivityEmbeddingUtils.SPLIT_RATIO, LayoutDirection.LOCALE); return rule; mSplitController.registerRule(placeholderRule); } @NonNull Loading src/com/android/settings/homepage/SettingsHomepageActivity.java +80 −0 Original line number Diff line number Diff line Loading @@ -18,8 +18,14 @@ package com.android.settings.homepage; import android.animation.LayoutTransition; import android.app.ActivityManager; import android.app.PendingIntent; import android.app.settings.SettingsEnums; import android.content.ComponentName; import android.content.Intent; import android.content.pm.PackageManager; import android.os.Bundle; import android.provider.Settings; import android.text.TextUtils; import android.util.FeatureFlagUtils; import android.util.Log; import android.view.View; Loading @@ -31,21 +37,33 @@ import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentActivity; import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentTransaction; import androidx.window.embedding.SplitController; import com.android.settings.R; import com.android.settings.Utils; import com.android.settings.accounts.AvatarViewMixin; import com.android.settings.core.CategoryMixin; import com.android.settings.core.FeatureFlags; import com.android.settings.activityembedding.ActivityEmbeddingRulesController; import com.android.settings.activityembedding.ActivityEmbeddingUtils; import com.android.settings.homepage.contextualcards.ContextualCardsFragment; import com.android.settings.overlay.FeatureFactory; import com.android.settingslib.core.lifecycle.HideNonSystemOverlayMixin; import java.net.URISyntaxException; /** Settings homepage activity */ public class SettingsHomepageActivity extends FragmentActivity implements CategoryMixin.CategoryHandler { private static final String TAG = "SettingsHomepageActivity"; // Put true value to the intent when startActivity for a deep link intent from this Activity. public static final String EXTRA_IS_FROM_SETTINGS_HOMEPAGE = "is_from_settings_homepage"; // An alias class name of SettingsHomepageActivity. private static final String ALIAS_DEEP_LINK = "com.android.settings.DeepLinkHomepageActivity"; private static final long HOMEPAGE_LOADING_TIMEOUT_MS = 300; private View mHomepageView; Loading Loading @@ -105,6 +123,20 @@ public class SettingsHomepageActivity extends FragmentActivity implements showFragment(new TopLevelSettings(), R.id.main_content); ((FrameLayout) findViewById(R.id.main_content)) .getLayoutTransition().enableTransitionType(LayoutTransition.CHANGING); // Launch the intent from deep link for large screen devices. launchDeepLinkIntentToRight(); } @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); // When it's large screen 2-pane and Settings app is in background. Receiving a Intent // in this Activity will not finish nor onCreate. setIntent here for this case. setIntent(intent); // Launch the intent from deep link for large screen devices. launchDeepLinkIntentToRight(); } private void showSuggestionFragment() { Loading Loading @@ -141,6 +173,54 @@ public class SettingsHomepageActivity extends FragmentActivity implements fragmentTransaction.commit(); } private void launchDeepLinkIntentToRight() { if (!ActivityEmbeddingUtils.isEmbeddingActivityEnabled(this)) { return; } final Intent intent = getIntent(); if (intent == null || !TextUtils.equals(intent.getAction(), Settings.ACTION_SETTINGS_LARGE_SCREEN_DEEP_LINK)) { return; } final String intentUriString = intent.getStringExtra( Settings.EXTRA_SETTINGS_LARGE_SCREEN_DEEP_LINK_INTENT_URI); if (TextUtils.isEmpty(intentUriString)) { Log.e(TAG, "No EXTRA_SETTINGS_LARGE_SCREEN_DEEP_LINK_INTENT_URI to deep link"); finish(); return; } final Intent targetIntent; try { targetIntent = Intent.parseUri(intentUriString, Intent.URI_INTENT_SCHEME); } catch (URISyntaxException e) { Log.e(TAG, "Failed to parse deep link intent: " + e); finish(); return; } final ComponentName targetComponentName = targetIntent.resolveActivity(getPackageManager()); if (targetComponentName == null) { Log.e(TAG, "No valid target for the deep link intent: " + targetIntent); finish(); return; } targetIntent.setFlags(targetIntent.getFlags() & ~Intent.FLAG_ACTIVITY_NEW_TASK); targetIntent.putExtra(EXTRA_IS_FROM_SETTINGS_HOMEPAGE, true); // Set 2-pane pair rule for the external deep link page. ActivityEmbeddingRulesController.registerTwoPanePairRule(this, new ComponentName(Utils.SETTINGS_PACKAGE_NAME, ALIAS_DEEP_LINK), targetComponentName, true /* finishPrimaryWithSecondary */, true /* finishSecondaryWithPrimary */); startActivity(targetIntent); } private void initHomepageContainer() { final View view = findViewById(R.id.homepage_container); // Prevent inner RecyclerView gets focus and invokes scrolling. Loading Loading
AndroidManifest.xml +13 −0 Original line number Diff line number Diff line Loading @@ -107,6 +107,8 @@ <uses-permission android:name="android.permission.READ_DREAM_STATE" /> <uses-permission android:name="android.permission.READ_DREAM_SUPPRESSION" /> <uses-permission android:name="android.permission.MANAGE_APP_HIBERNATION" /> <uses-permission android:name="android.permission.LAUNCH_TWO_PANE_SETTINGS_DEEP_LINK" /> <uses-permission android:name="android.permission.ALLOW_PLACE_IN_TWO_PANE_SETTINGS" /> <application android:name=".SettingsApplication" Loading Loading @@ -172,6 +174,17 @@ <meta-data android:name="android.app.shortcuts" android:resource="@xml/shortcuts"/> </activity-alias> <!-- Alias for SettingsHomepageActivity which works for deep link page in 2-panel. --> <activity-alias android:name="DeepLinkHomepageActivity" android:label="@string/settings_label_launcher" android:exported="true" android:targetActivity=".homepage.SettingsHomepageActivity"> <intent-filter> <action android:name="android.settings.SETTINGS_LARGE_SCREEN_DEEP_LINK" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity-alias> <receiver android:name=".SettingsInitialize" android:exported="true"> <intent-filter> Loading
src/com/android/settings/SettingsActivity.java +23 −0 Original line number Diff line number Diff line Loading @@ -58,6 +58,8 @@ import com.android.settings.core.SettingsBaseActivity; import com.android.settings.core.SubSettingLauncher; import com.android.settings.core.gateway.SettingsGateway; import com.android.settings.dashboard.DashboardFeatureProvider; import com.android.settings.activityembedding.ActivityEmbeddingUtils; import com.android.settings.homepage.SettingsHomepageActivity; import com.android.settings.homepage.TopLevelSettings; import com.android.settings.overlay.FeatureFactory; import com.android.settings.wfd.WifiDisplaySettings; Loading Loading @@ -240,7 +242,22 @@ public class SettingsActivity extends SettingsBaseActivity // Should happen before any call to getIntent() getMetaData(); // If it's a deep link intent, start the Activity from SettingsHomepageActivity for 2-pane. final Intent intent = getIntent(); final boolean isFromSettingsHomepage = intent.getBooleanExtra( SettingsHomepageActivity.EXTRA_IS_FROM_SETTINGS_HOMEPAGE, /* defaultValue */ false); if (ActivityEmbeddingUtils.isEmbeddingActivityEnabled(this) && !isFromSettingsHomepage && isOnlyOneActivityInActivityStack()) { final Intent trampolineIntent = new Intent(android.provider.Settings.ACTION_SETTINGS_LARGE_SCREEN_DEEP_LINK); trampolineIntent.putExtra( android.provider.Settings.EXTRA_SETTINGS_LARGE_SCREEN_DEEP_LINK_INTENT_URI, intent.toUri(Intent.URI_INTENT_SCHEME)); startActivity(trampolineIntent); finish(); return; } if (intent.hasExtra(EXTRA_UI_OPTIONS)) { getWindow().setUiOptions(intent.getIntExtra(EXTRA_UI_OPTIONS, 0)); } Loading Loading @@ -347,6 +364,12 @@ public class SettingsActivity extends SettingsBaseActivity } } private boolean isOnlyOneActivityInActivityStack() { final ActivityManager activityManager = getSystemService(ActivityManager.class); List<ActivityManager.RunningTaskInfo> taskList = activityManager.getRunningTasks(2); return taskList.get(0).numActivities == 1; } /** Returns the initial fragment name that the activity will launch. */ @VisibleForTesting public String getInitialFragmentName(Intent intent) { Loading
src/com/android/settings/activityembedding/ActivityEmbeddingRulesController.java +26 −24 Original line number Diff line number Diff line Loading @@ -60,12 +60,34 @@ public class ActivityEmbeddingRulesController { mSplitController.clearRegisteredRules(); // Set a placeholder for home page. mSplitController.registerRule(getHomepagePlaceholderRule()); registerHomepagePlaceholderRule(); // Set subsettings rule. mSplitController.registerRule(getSubSettingsPairRule()); registerTwoPanePairRule(mContext, getComponentName(Settings.class), getComponentName(SubSettings.class), true /* finishPrimaryWithSecondary */, true /* finishSecondaryWithPrimary */); } private SplitPlaceholderRule getHomepagePlaceholderRule() { /** Register a SplitPairRule for 2-pane. */ public static void registerTwoPanePairRule(Context context, ComponentName primary, ComponentName secondary, boolean finishPrimaryWithSecondary, boolean finishSecondaryWithPrimary) { final Set<SplitPairFilter> filters = new HashSet<>(); filters.add(new SplitPairFilter(primary, secondary, null /* secondaryActivityIntentAction */, null /* secondaryActivityIntentCategory */)); new SplitController(context).registerRule(new SplitPairRule(filters, finishPrimaryWithSecondary, finishSecondaryWithPrimary, true /* clearTop */, ActivityEmbeddingUtils.getMinCurrentScreenSplitWidthPx(context), ActivityEmbeddingUtils.getMinSmallestScreenSplitWidthPx(context), ActivityEmbeddingUtils.SPLIT_RATIO, LayoutDirection.LOCALE)); } private void registerHomepagePlaceholderRule() { final Set<ActivityFilter> activityFilters = new HashSet<>(); activityFilters.add(new ActivityFilter(getComponentName(Settings.class))); final Intent intent = new Intent(); Loading @@ -78,27 +100,7 @@ public class ActivityEmbeddingRulesController { ActivityEmbeddingUtils.SPLIT_RATIO, LayoutDirection.LOCALE); return placeholderRule; } private SplitPairRule getSubSettingsPairRule() { final Set<SplitPairFilter> pairFilters = new HashSet<>(); pairFilters.add(new SplitPairFilter( getComponentName(Settings.class), getComponentName(SubSettings.class), null /* secondaryActivityIntentAction */, null /* secondaryActivityIntentCategory */)); final SplitPairRule rule = new SplitPairRule( pairFilters, true /* finishPrimaryWithSecondary */, true /* finishSecondaryWithPrimary */, true /* clearTop */, ActivityEmbeddingUtils.getMinCurrentScreenSplitWidthPx(mContext), ActivityEmbeddingUtils.getMinSmallestScreenSplitWidthPx(mContext), ActivityEmbeddingUtils.SPLIT_RATIO, LayoutDirection.LOCALE); return rule; mSplitController.registerRule(placeholderRule); } @NonNull Loading
src/com/android/settings/homepage/SettingsHomepageActivity.java +80 −0 Original line number Diff line number Diff line Loading @@ -18,8 +18,14 @@ package com.android.settings.homepage; import android.animation.LayoutTransition; import android.app.ActivityManager; import android.app.PendingIntent; import android.app.settings.SettingsEnums; import android.content.ComponentName; import android.content.Intent; import android.content.pm.PackageManager; import android.os.Bundle; import android.provider.Settings; import android.text.TextUtils; import android.util.FeatureFlagUtils; import android.util.Log; import android.view.View; Loading @@ -31,21 +37,33 @@ import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentActivity; import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentTransaction; import androidx.window.embedding.SplitController; import com.android.settings.R; import com.android.settings.Utils; import com.android.settings.accounts.AvatarViewMixin; import com.android.settings.core.CategoryMixin; import com.android.settings.core.FeatureFlags; import com.android.settings.activityembedding.ActivityEmbeddingRulesController; import com.android.settings.activityembedding.ActivityEmbeddingUtils; import com.android.settings.homepage.contextualcards.ContextualCardsFragment; import com.android.settings.overlay.FeatureFactory; import com.android.settingslib.core.lifecycle.HideNonSystemOverlayMixin; import java.net.URISyntaxException; /** Settings homepage activity */ public class SettingsHomepageActivity extends FragmentActivity implements CategoryMixin.CategoryHandler { private static final String TAG = "SettingsHomepageActivity"; // Put true value to the intent when startActivity for a deep link intent from this Activity. public static final String EXTRA_IS_FROM_SETTINGS_HOMEPAGE = "is_from_settings_homepage"; // An alias class name of SettingsHomepageActivity. private static final String ALIAS_DEEP_LINK = "com.android.settings.DeepLinkHomepageActivity"; private static final long HOMEPAGE_LOADING_TIMEOUT_MS = 300; private View mHomepageView; Loading Loading @@ -105,6 +123,20 @@ public class SettingsHomepageActivity extends FragmentActivity implements showFragment(new TopLevelSettings(), R.id.main_content); ((FrameLayout) findViewById(R.id.main_content)) .getLayoutTransition().enableTransitionType(LayoutTransition.CHANGING); // Launch the intent from deep link for large screen devices. launchDeepLinkIntentToRight(); } @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); // When it's large screen 2-pane and Settings app is in background. Receiving a Intent // in this Activity will not finish nor onCreate. setIntent here for this case. setIntent(intent); // Launch the intent from deep link for large screen devices. launchDeepLinkIntentToRight(); } private void showSuggestionFragment() { Loading Loading @@ -141,6 +173,54 @@ public class SettingsHomepageActivity extends FragmentActivity implements fragmentTransaction.commit(); } private void launchDeepLinkIntentToRight() { if (!ActivityEmbeddingUtils.isEmbeddingActivityEnabled(this)) { return; } final Intent intent = getIntent(); if (intent == null || !TextUtils.equals(intent.getAction(), Settings.ACTION_SETTINGS_LARGE_SCREEN_DEEP_LINK)) { return; } final String intentUriString = intent.getStringExtra( Settings.EXTRA_SETTINGS_LARGE_SCREEN_DEEP_LINK_INTENT_URI); if (TextUtils.isEmpty(intentUriString)) { Log.e(TAG, "No EXTRA_SETTINGS_LARGE_SCREEN_DEEP_LINK_INTENT_URI to deep link"); finish(); return; } final Intent targetIntent; try { targetIntent = Intent.parseUri(intentUriString, Intent.URI_INTENT_SCHEME); } catch (URISyntaxException e) { Log.e(TAG, "Failed to parse deep link intent: " + e); finish(); return; } final ComponentName targetComponentName = targetIntent.resolveActivity(getPackageManager()); if (targetComponentName == null) { Log.e(TAG, "No valid target for the deep link intent: " + targetIntent); finish(); return; } targetIntent.setFlags(targetIntent.getFlags() & ~Intent.FLAG_ACTIVITY_NEW_TASK); targetIntent.putExtra(EXTRA_IS_FROM_SETTINGS_HOMEPAGE, true); // Set 2-pane pair rule for the external deep link page. ActivityEmbeddingRulesController.registerTwoPanePairRule(this, new ComponentName(Utils.SETTINGS_PACKAGE_NAME, ALIAS_DEEP_LINK), targetComponentName, true /* finishPrimaryWithSecondary */, true /* finishSecondaryWithPrimary */); startActivity(targetIntent); } private void initHomepageContainer() { final View view = findViewById(R.id.homepage_container); // Prevent inner RecyclerView gets focus and invokes scrolling. Loading