diff --git a/AndroidManifest.xml b/AndroidManifest.xml index bb72e950d51..638340e4498 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -1197,6 +1197,8 @@ + @@ -1223,6 +1225,8 @@ + @@ -1243,6 +1247,8 @@ + @@ -1266,6 +1272,8 @@ + + + @@ -1396,6 +1408,8 @@ + @@ -1417,6 +1431,8 @@ + @@ -2245,6 +2261,8 @@ + + 20sp + + 200dp + 20dp 12dp diff --git a/src/com/android/settings/SettingsActivity.java b/src/com/android/settings/SettingsActivity.java index 226e1de1895..957efdf7bed 100644 --- a/src/com/android/settings/SettingsActivity.java +++ b/src/com/android/settings/SettingsActivity.java @@ -451,6 +451,11 @@ public class SettingsActivity extends SettingsBaseActivity return false; } + if (intent.getBooleanExtra(SettingsHomepageActivity.EXTRA_IS_FROM_SETTINGS_HOMEPAGE, + /* defaultValue */ false)) { + return false; + } + if (TextUtils.equals(intent.getAction(), Intent.ACTION_CREATE_SHORTCUT)) { // Returns false to show full screen for Intent.ACTION_CREATE_SHORTCUT because // - Launcher startActivityForResult for Intent.ACTION_CREATE_SHORTCUT and activity diff --git a/src/com/android/settings/activityembedding/ActivityEmbeddingRulesController.java b/src/com/android/settings/activityembedding/ActivityEmbeddingRulesController.java index 974ec2cbe2a..d3d53a85143 100644 --- a/src/com/android/settings/activityembedding/ActivityEmbeddingRulesController.java +++ b/src/com/android/settings/activityembedding/ActivityEmbeddingRulesController.java @@ -73,6 +73,9 @@ public class ActivityEmbeddingRulesController { boolean finishPrimaryWithSecondary, boolean finishSecondaryWithPrimary, boolean clearTop) { + if (!ActivityEmbeddingUtils.isEmbeddingActivityEnabled(context)) { + return; + } final Set filters = new HashSet<>(); filters.add(new SplitPairFilter(primaryComponent, secondaryComponent, secondaryIntentAction)); @@ -87,18 +90,55 @@ public class ActivityEmbeddingRulesController { LayoutDirection.LOCALE)); } + /** + * Register a new SplitPairRule for Settings home. Because homepage is able to be opened by + * {@link Settings} or {@link SettingsHomepageActivity}, we register split rule twice for + * two cases. + */ + public static void registerTwoPanePairRuleForSettingsHome(Context context, + ComponentName secondaryComponent, + String secondaryIntentAction, + boolean clearTop) { + + registerTwoPanePairRule( + context, + getComponentName(context, Settings.class), + secondaryComponent, + secondaryIntentAction, + true /* finishPrimaryWithSecondary */, + true /* finishSecondaryWithPrimary */, + clearTop); + + registerTwoPanePairRule( + context, + new ComponentName(Utils.SETTINGS_PACKAGE_NAME, + SettingsHomepageActivity.ALIAS_DEEP_LINK), + secondaryComponent, + secondaryIntentAction, + true /* finishPrimaryWithSecondary */, + true /* finishSecondaryWithPrimary */, + clearTop); + + registerTwoPanePairRule( + context, + getComponentName(context, SettingsHomepageActivity.class), + secondaryComponent, + secondaryIntentAction, + true /* finishPrimaryWithSecondary */, + true /* finishSecondaryWithPrimary */, + clearTop); + } + /** Register a SplitPairRule for SubSettings if the device supports 2-pane. */ - public static void registerSubSettingsPairRuleIfNeeded(Context context, boolean clearTop) { + public static void registerSubSettingsPairRule(Context context, boolean clearTop) { if (!ActivityEmbeddingUtils.isEmbeddingActivityEnabled(context)) { return; } - registerTwoPanePairRule(context, - getComponentName(context, Settings.class), + registerTwoPanePairRuleForSettingsHome( + context, getComponentName(context, SubSettings.class), null /* secondaryIntentAction */, - true /* finishPrimaryWithSecondary */, - true /* finishSecondaryWithPrimary */, clearTop); } @@ -140,7 +180,7 @@ public class ActivityEmbeddingRulesController { @NonNull private static ComponentName getComponentName(Context context, - Class activityClass) { + Class activityClass) { return new ComponentName(context.getPackageName(), activityClass.getName()); } } diff --git a/src/com/android/settings/dashboard/DashboardFeatureProviderImpl.java b/src/com/android/settings/dashboard/DashboardFeatureProviderImpl.java index 951eb3c1b40..3d1381d6867 100644 --- a/src/com/android/settings/dashboard/DashboardFeatureProviderImpl.java +++ b/src/com/android/settings/dashboard/DashboardFeatureProviderImpl.java @@ -175,14 +175,10 @@ public class DashboardFeatureProviderImpl implements DashboardFeatureProvider { if (fragment instanceof TopLevelSettings && ActivityEmbeddingUtils.isEmbeddingActivityEnabled(mContext)) { // Register the rule for injected apps. - ActivityEmbeddingRulesController.registerTwoPanePairRule(mContext, - new ComponentName(activity.getPackageName(), - com.android.settings.Settings.class.getName()), - new ComponentName(tile.getPackageName(), - tile.getComponentName()), + ActivityEmbeddingRulesController.registerTwoPanePairRuleForSettingsHome( + mContext, + new ComponentName(tile.getPackageName(), tile.getComponentName()), null /* secondaryIntentAction */, - true /* finishPrimaryWithSecondary */, - true /* finishSecondaryWithPrimary */, true /* clearTop */); // Highlight preference ui. diff --git a/src/com/android/settings/display/TopLevelWallpaperPreferenceController.java b/src/com/android/settings/display/TopLevelWallpaperPreferenceController.java index 2e59725cdc1..7640d08716f 100644 --- a/src/com/android/settings/display/TopLevelWallpaperPreferenceController.java +++ b/src/com/android/settings/display/TopLevelWallpaperPreferenceController.java @@ -31,6 +31,7 @@ import androidx.preference.Preference; import androidx.preference.PreferenceScreen; import com.android.settings.R; +import com.android.settings.activityembedding.ActivityEmbeddingRulesController; import com.android.settings.activityembedding.ActivityEmbeddingUtils; import com.android.settings.core.BasePreferenceController; import com.android.settingslib.RestrictedLockUtilsInternal; @@ -102,6 +103,11 @@ public class TopLevelWallpaperPreferenceController extends BasePreferenceControl mContext)) { intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); } + ActivityEmbeddingRulesController.registerTwoPanePairRuleForSettingsHome( + mContext, + intent.getComponent(), + null /* secondaryIntentAction */, + true /* clearTop */); preference.getContext().startActivity(intent); return true; } diff --git a/src/com/android/settings/homepage/SettingsHomepageActivity.java b/src/com/android/settings/homepage/SettingsHomepageActivity.java index 0322cfa8b5e..051204dc767 100644 --- a/src/com/android/settings/homepage/SettingsHomepageActivity.java +++ b/src/com/android/settings/homepage/SettingsHomepageActivity.java @@ -63,6 +63,10 @@ public class SettingsHomepageActivity extends FragmentActivity implements private static final String TAG = "SettingsHomepageActivity"; + // Additional extra of Settings#ACTION_SETTINGS_LARGE_SCREEN_DEEP_LINK. + // 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"; + // Additional extra of Settings#ACTION_SETTINGS_LARGE_SCREEN_DEEP_LINK. // Set & get Uri of the Intent separately to prevent failure of Intent#ParseUri. public static final String EXTRA_SETTINGS_LARGE_SCREEN_DEEP_LINK_INTENT_DATA = @@ -95,7 +99,9 @@ public class SettingsHomepageActivity extends FragmentActivity implements if (mHomepageView == null) { return false; } else { - mLoadedListeners.add(listener); + if (!mLoadedListeners.contains(listener)) { + mLoadedListeners.add(listener); + } return true; } } @@ -109,11 +115,13 @@ public class SettingsHomepageActivity extends FragmentActivity implements return; } Log.i(TAG, "showHomepageWithSuggestion: " + showSuggestion); + final View homepageView = mHomepageView; mSuggestionView.setVisibility(showSuggestion ? View.VISIBLE : View.GONE); - mHomepageView.setVisibility(View.VISIBLE); mHomepageView = null; + mLoadedListeners.forEach(listener -> listener.onHomepageLoaded()); mLoadedListeners.clear(); + homepageView.setVisibility(View.VISIBLE); } @Override @@ -195,7 +203,7 @@ public class SettingsHomepageActivity extends FragmentActivity implements mSuggestionView = findViewById(R.id.suggestion_content); mHomepageView = findViewById(R.id.settings_homepage_container); // Hide the homepage for preparing the suggestion. - mHomepageView.setVisibility(View.GONE); + mHomepageView.setVisibility(View.INVISIBLE); // Schedule a timer to show the homepage and hide the suggestion on timeout. mHomepageView.postDelayed(() -> showHomepageWithSuggestion(false), HOMEPAGE_LOADING_TIMEOUT_MS); @@ -264,6 +272,7 @@ public class SettingsHomepageActivity extends FragmentActivity implements // Sender of intent may want to send intent extra data to the destination of targetIntent. targetIntent.replaceExtras(intent); + targetIntent.putExtra(EXTRA_IS_FROM_SETTINGS_HOMEPAGE, true); targetIntent.putExtra(SettingsActivity.EXTRA_IS_FROM_SLICE, false); targetIntent.setData(intent.getParcelableExtra( diff --git a/src/com/android/settings/homepage/TopLevelSettings.java b/src/com/android/settings/homepage/TopLevelSettings.java index e9c7ef89668..548b3c4bec0 100644 --- a/src/com/android/settings/homepage/TopLevelSettings.java +++ b/src/com/android/settings/homepage/TopLevelSettings.java @@ -100,7 +100,7 @@ public class TopLevelSettings extends DashboardFragment implements @Override public boolean onPreferenceTreeClick(Preference preference) { // Register SplitPairRule for SubSettings. - ActivityEmbeddingRulesController.registerSubSettingsPairRuleIfNeeded(getContext(), + ActivityEmbeddingRulesController.registerSubSettingsPairRule(getContext(), true /* clearTop */); setHighlightPreferenceKey(preference.getKey()); @@ -201,7 +201,8 @@ public class TopLevelSettings extends DashboardFragment implements @Override protected RecyclerView.Adapter onCreateAdapter(PreferenceScreen preferenceScreen) { - if (!ActivityEmbeddingUtils.isEmbeddingActivityEnabled(getContext())) { + if (!ActivityEmbeddingUtils.isEmbeddingActivityEnabled(getContext()) + || !(getActivity() instanceof SettingsHomepageActivity)) { return super.onCreateAdapter(preferenceScreen); } diff --git a/src/com/android/settings/password/ChooseLockPattern.java b/src/com/android/settings/password/ChooseLockPattern.java index 8464a2ffd7c..016906aea10 100644 --- a/src/com/android/settings/password/ChooseLockPattern.java +++ b/src/com/android/settings/password/ChooseLockPattern.java @@ -21,6 +21,7 @@ import static android.view.View.ACCESSIBILITY_LIVE_REGION_POLITE; import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_UNIFICATION_PROFILE_CREDENTIAL; import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_UNIFICATION_PROFILE_ID; +import android.annotation.SuppressLint; import android.app.Activity; import android.app.settings.SettingsEnums; import android.content.Context; @@ -35,6 +36,7 @@ import android.util.Pair; import android.util.TypedValue; import android.view.KeyEvent; import android.view.LayoutInflater; +import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; @@ -491,11 +493,18 @@ public class ChooseLockPattern extends SettingsActivity { getActivity().setTitle(msg); } + @SuppressLint("ClickableViewAccessibility") @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { final GlifLayout layout = (GlifLayout) inflater.inflate( R.layout.choose_lock_pattern, container, false); + layout.findViewById(R.id.lockPattern).setOnTouchListener((v, event) -> { + if (event.getAction() == MotionEvent.ACTION_DOWN) { + v.getParent().requestDisallowInterceptTouchEvent(true); + } + return false; + }); updateActivityTitle(); layout.setHeaderText(getActivity().getTitle()); layout.getHeaderTextView().setAccessibilityLiveRegion(ACCESSIBILITY_LIVE_REGION_POLITE); diff --git a/src/com/android/settings/search/SearchResultTrampoline.java b/src/com/android/settings/search/SearchResultTrampoline.java index d20a2ea860d..a770126ab82 100644 --- a/src/com/android/settings/search/SearchResultTrampoline.java +++ b/src/com/android/settings/search/SearchResultTrampoline.java @@ -94,17 +94,16 @@ public class SearchResultTrampoline extends Activity { if (!ActivityEmbeddingUtils.isEmbeddingActivityEnabled(this)) { startActivity(intent); - } else if (isFromSettingsIntelligence(callingActivity)) { + } else if (isSettingsIntelligence(callingActivity)) { // Register SplitPairRule for SubSettings, set clearTop false to prevent unexpected back // navigation behavior. - ActivityEmbeddingRulesController.registerSubSettingsPairRuleIfNeeded(this, + ActivityEmbeddingRulesController.registerSubSettingsPairRule(this, false /* clearTop */); // TODO: pass menu key to homepage intent.setFlags(intent.getFlags() & ~Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(intent); } else { // Two-pane case - intent.setFlags(intent.getFlags() & ~Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(SettingsActivity.getTrampolineIntent(intent, highlightMenuKey)); } @@ -112,7 +111,7 @@ public class SearchResultTrampoline extends Activity { finish(); } - private boolean isFromSettingsIntelligence(ComponentName callingActivity) { + private boolean isSettingsIntelligence(ComponentName callingActivity) { return callingActivity != null && TextUtils.equals( callingActivity.getPackageName(), FeatureFactory.getFactory(this).getSearchFeatureProvider() diff --git a/src/com/android/settings/widget/HighlightableTopLevelPreferenceAdapter.java b/src/com/android/settings/widget/HighlightableTopLevelPreferenceAdapter.java index bf92bbdf679..bdf08861682 100644 --- a/src/com/android/settings/widget/HighlightableTopLevelPreferenceAdapter.java +++ b/src/com/android/settings/widget/HighlightableTopLevelPreferenceAdapter.java @@ -38,7 +38,8 @@ import com.android.settings.homepage.SettingsHomepageActivity; /** * Adapter for highlighting top level preferences */ -public class HighlightableTopLevelPreferenceAdapter extends PreferenceGroupAdapter { +public class HighlightableTopLevelPreferenceAdapter extends PreferenceGroupAdapter implements + SettingsHomepageActivity.HomepageLoadedListener { private static final String TAG = "HighlightableTopLevelAdapter"; @@ -60,6 +61,7 @@ public class HighlightableTopLevelPreferenceAdapter extends PreferenceGroupAdapt private String mHighlightKey; private String mPreviousHighlightKey; private int mHighlightPosition = RecyclerView.NO_POSITION; + private int mScrollPosition = RecyclerView.NO_POSITION; private boolean mHighlightNeeded; private boolean mScrolled; @@ -135,9 +137,11 @@ public class HighlightableTopLevelPreferenceAdapter extends PreferenceGroupAdapt return; } + // Scroll before highlight if needed. final boolean highlightNeeded = isHighlightNeeded(); if (highlightNeeded) { - scrollToPositionIfNeeded(position); + mScrollPosition = position; + scroll(); } // Turn on/off highlight when screen split mode is changed. @@ -189,26 +193,29 @@ public class HighlightableTopLevelPreferenceAdapter extends PreferenceGroupAdapt requestHighlight(); } - private void scrollToPositionIfNeeded(int position) { - if (mScrolled || position < 0) { + @Override + public void onHomepageLoaded() { + scroll(); + } + + private void scroll() { + if (mScrolled || mScrollPosition < 0) { return; } - if (mHomepageActivity.registerHomepageLoadedListenerIfNeeded( - () -> scrollToPositionIfNeeded(position))) { + if (mHomepageActivity.registerHomepageLoadedListenerIfNeeded(this)) { return; } // Only when the recyclerView is loaded, it can be scrolled - final View view = mRecyclerView.getChildAt(position); + final View view = mRecyclerView.getChildAt(mScrollPosition); if (view == null) { - mRecyclerView.postDelayed(() -> scrollToPositionIfNeeded(position), - DELAY_HIGHLIGHT_DURATION_MILLIS); + mRecyclerView.postDelayed(() -> scroll(), DELAY_HIGHLIGHT_DURATION_MILLIS); return; } mScrolled = true; - Log.d(TAG, "Scroll to position " + position); + Log.d(TAG, "Scroll to position " + mScrollPosition); // Scroll to the top to reset the position. mRecyclerView.nestedScrollBy(0, -mRecyclerView.getHeight());