After users select a shortcut item in CreateShortcutActivity,
launchers need to get result from CreateShortcutActivity.
For large screen devices, Settings deep link will start
DeepLinkHomepageActivity and then DeepLinkHomepageActivity
starts the deep link page. The CreateShortcutActivity result
deos not forward to launcher and there is no shortcut added.
This change uses Intent.FLAG_ACTIVITY_FORWARD_RESULT to
forward result from CreateShortcutActivity to launcher.
Bug: 200889769
Test: manual
Long click launcher -> Widget -> Settings ->
select an item and check if it adds a short on launcher.
Change-Id: Idd5fc642be5c1fb2f747316c3ddcd9b7f0b33852
249 lines
9.9 KiB
Java
249 lines
9.9 KiB
Java
/*
|
|
* Copyright (C) 2018 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
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.text.TextUtils;
|
|
import android.util.FeatureFlagUtils;
|
|
import android.util.Log;
|
|
import android.view.View;
|
|
import android.widget.FrameLayout;
|
|
import android.widget.ImageView;
|
|
import android.widget.Toolbar;
|
|
|
|
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.Settings;
|
|
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.
|
|
public static final String ALIAS_DEEP_LINK = "com.android.settings.DeepLinkHomepageActivity";
|
|
|
|
private static final long HOMEPAGE_LOADING_TIMEOUT_MS = 300;
|
|
|
|
private View mHomepageView;
|
|
private View mSuggestionView;
|
|
private CategoryMixin mCategoryMixin;
|
|
|
|
@Override
|
|
public CategoryMixin getCategoryMixin() {
|
|
return mCategoryMixin;
|
|
}
|
|
|
|
/**
|
|
* Shows the homepage and shows/hides the suggestion together. Only allows to be executed once
|
|
* to avoid the flicker caused by the suggestion suddenly appearing/disappearing.
|
|
*/
|
|
public void showHomepageWithSuggestion(boolean showSuggestion) {
|
|
if (mHomepageView == null) {
|
|
return;
|
|
}
|
|
Log.i(TAG, "showHomepageWithSuggestion: " + showSuggestion);
|
|
mSuggestionView.setVisibility(showSuggestion ? View.VISIBLE : View.GONE);
|
|
mHomepageView.setVisibility(View.VISIBLE);
|
|
mHomepageView = null;
|
|
}
|
|
|
|
@Override
|
|
protected void onCreate(Bundle savedInstanceState) {
|
|
super.onCreate(savedInstanceState);
|
|
setContentView(R.layout.settings_homepage_container);
|
|
|
|
final View appBar = findViewById(R.id.app_bar_container);
|
|
appBar.setMinimumHeight(getSearchBoxHeight());
|
|
initHomepageContainer();
|
|
|
|
final Toolbar toolbar = findViewById(R.id.search_action_bar);
|
|
FeatureFactory.getFactory(this).getSearchFeatureProvider()
|
|
.initSearchToolbar(this /* activity */, toolbar, SettingsEnums.SETTINGS_HOMEPAGE);
|
|
|
|
getLifecycle().addObserver(new HideNonSystemOverlayMixin(this));
|
|
mCategoryMixin = new CategoryMixin(this);
|
|
getLifecycle().addObserver(mCategoryMixin);
|
|
|
|
if (!getSystemService(ActivityManager.class).isLowRamDevice()) {
|
|
// Only allow features on high ram devices.
|
|
final ImageView avatarView = findViewById(R.id.account_avatar);
|
|
if (AvatarViewMixin.isAvatarSupported(this)) {
|
|
avatarView.setVisibility(View.VISIBLE);
|
|
getLifecycle().addObserver(new AvatarViewMixin(this, avatarView));
|
|
}
|
|
|
|
showSuggestionFragment();
|
|
|
|
if (FeatureFlagUtils.isEnabled(this, FeatureFlags.CONTEXTUAL_HOME)) {
|
|
showFragment(new ContextualCardsFragment(), R.id.contextual_cards_content);
|
|
}
|
|
}
|
|
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() {
|
|
final Class<? extends Fragment> fragment = FeatureFactory.getFactory(this)
|
|
.getSuggestionFeatureProvider(this).getContextualSuggestionFragment();
|
|
if (fragment == null) {
|
|
return;
|
|
}
|
|
|
|
mSuggestionView = findViewById(R.id.suggestion_content);
|
|
mHomepageView = findViewById(R.id.settings_homepage_container);
|
|
// Hide the homepage for preparing the suggestion.
|
|
mHomepageView.setVisibility(View.GONE);
|
|
// Schedule a timer to show the homepage and hide the suggestion on timeout.
|
|
mHomepageView.postDelayed(() -> showHomepageWithSuggestion(false),
|
|
HOMEPAGE_LOADING_TIMEOUT_MS);
|
|
try {
|
|
showFragment(fragment.getConstructor().newInstance(), R.id.suggestion_content);
|
|
} catch (Exception e) {
|
|
Log.w(TAG, "Cannot show fragment", e);
|
|
}
|
|
}
|
|
|
|
private void showFragment(Fragment fragment, int id) {
|
|
final FragmentManager fragmentManager = getSupportFragmentManager();
|
|
final FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
|
|
final Fragment showFragment = fragmentManager.findFragmentById(id);
|
|
|
|
if (showFragment == null) {
|
|
fragmentTransaction.add(id, fragment);
|
|
} else {
|
|
fragmentTransaction.show(showFragment);
|
|
}
|
|
fragmentTransaction.commit();
|
|
}
|
|
|
|
private void launchDeepLinkIntentToRight() {
|
|
if (!ActivityEmbeddingUtils.isEmbeddingActivityEnabled(this)) {
|
|
return;
|
|
}
|
|
|
|
final Intent intent = getIntent();
|
|
if (intent == null || !TextUtils.equals(intent.getAction(),
|
|
android.provider.Settings.ACTION_SETTINGS_LARGE_SCREEN_DEEP_LINK)) {
|
|
return;
|
|
}
|
|
|
|
final String intentUriString = intent.getStringExtra(
|
|
android.provider.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;
|
|
}
|
|
|
|
// To prevent launchDeepLinkIntentToRight again for configuration change.
|
|
intent.setAction(null);
|
|
|
|
targetIntent.setFlags(targetIntent.getFlags() & ~Intent.FLAG_ACTIVITY_NEW_TASK);
|
|
targetIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
|
|
|
|
// 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);
|
|
|
|
// Set 2-pane pair rule for the deep link page.
|
|
ActivityEmbeddingRulesController.registerTwoPanePairRule(this,
|
|
new ComponentName(Utils.SETTINGS_PACKAGE_NAME, ALIAS_DEEP_LINK),
|
|
targetComponentName,
|
|
true /* finishPrimaryWithSecondary */,
|
|
true /* finishSecondaryWithPrimary */);
|
|
ActivityEmbeddingRulesController.registerTwoPanePairRule(this,
|
|
new ComponentName(Settings.class.getPackageName(), Settings.class.getName()),
|
|
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.
|
|
view.setFocusableInTouchMode(true);
|
|
view.requestFocus();
|
|
}
|
|
|
|
private int getSearchBoxHeight() {
|
|
final int searchBarHeight = getResources().getDimensionPixelSize(R.dimen.search_bar_height);
|
|
final int searchBarMargin = getResources().getDimensionPixelSize(R.dimen.search_bar_margin);
|
|
return searchBarHeight + searchBarMargin * 2;
|
|
}
|
|
}
|