From 3515bc72594137050dd8c8d13f7b19df1cc76cec Mon Sep 17 00:00:00 2001 From: Raff Tsai Date: Tue, 19 Jun 2018 17:25:31 +0800 Subject: [PATCH] First commit of dynamic home page feature - Add SettingsHomepageActivity - Add feature flag - Use com.google.android.material_material library Change-Id: I325be249f739d3b03dc2f0d722319f5771e2313b --- Android.mk | 1 + AndroidManifest.xml | 9 +- res/drawable/ic_list_24dp.xml | 24 +++ res/layout/search_bar.xml | 50 ++++++ res/layout/settings_homepage.xml | 77 +++++++++ res/layout/settings_main_dashboard.xml | 33 +--- res/values/colors.xml | 4 + res/values/dimens.xml | 8 + res/values/themes.xml | 5 + .../settings/SettingsHomepageActivity.java | 61 +++++++ .../android/settings/core/FeatureFlags.java | 1 + .../settings/homepage/HomepageFragment.java | 150 ++++++++++++++++++ 12 files changed, 392 insertions(+), 31 deletions(-) create mode 100644 res/drawable/ic_list_24dp.xml create mode 100644 res/layout/search_bar.xml create mode 100644 res/layout/settings_homepage.xml create mode 100644 src/com/android/settings/SettingsHomepageActivity.java create mode 100644 src/com/android/settings/homepage/HomepageFragment.java diff --git a/Android.mk b/Android.mk index 96b5befd056..a573378faea 100644 --- a/Android.mk +++ b/Android.mk @@ -32,6 +32,7 @@ LOCAL_STATIC_ANDROID_LIBRARIES := \ androidx.preference_preference \ androidx.recyclerview_recyclerview \ androidx.legacy_legacy-preference-v14 \ + com.google.android.material_material \ LOCAL_JAVA_LIBRARIES := \ bouncycastle \ diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 3b6d4f8cd6f..19c8e5eb6a5 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -123,12 +123,19 @@ android:value="true" /> + + + + android:targetActivity=".SettingsHomepageActivity"> diff --git a/res/drawable/ic_list_24dp.xml b/res/drawable/ic_list_24dp.xml new file mode 100644 index 00000000000..03f4af0ba5d --- /dev/null +++ b/res/drawable/ic_list_24dp.xml @@ -0,0 +1,24 @@ + + + + + diff --git a/res/layout/search_bar.xml b/res/layout/search_bar.xml new file mode 100644 index 00000000000..9f8b6307214 --- /dev/null +++ b/res/layout/search_bar.xml @@ -0,0 +1,50 @@ + + + + + + + + + \ No newline at end of file diff --git a/res/layout/settings_homepage.xml b/res/layout/settings_homepage.xml new file mode 100644 index 00000000000..b944cebdd65 --- /dev/null +++ b/res/layout/settings_homepage.xml @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/res/layout/settings_main_dashboard.xml b/res/layout/settings_main_dashboard.xml index b14f73e147e..39940925e2b 100644 --- a/res/layout/settings_main_dashboard.xml +++ b/res/layout/settings_main_dashboard.xml @@ -23,36 +23,9 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> - - - - - - - + + + #fdd835 #f44336 + + #F1F3F4 + #F8F9FA + diff --git a/res/values/dimens.xml b/res/values/dimens.xml index 30d1e6c36e5..981893d1562 100755 --- a/res/values/dimens.xml +++ b/res/values/dimens.xml @@ -128,6 +128,8 @@ 48dp 2dp 16dp + 2dp + 64dp 16dp @@ -328,4 +330,10 @@ 18sp 14sp + + 90dp + 56dp + 34dp + 68dp + diff --git a/res/values/themes.xml b/res/values/themes.xml index 8c3864967e4..4d911563bfe 100644 --- a/res/values/themes.xml +++ b/res/values/themes.xml @@ -367,4 +367,9 @@ true + + diff --git a/src/com/android/settings/SettingsHomepageActivity.java b/src/com/android/settings/SettingsHomepageActivity.java new file mode 100644 index 00000000000..7eda621ea43 --- /dev/null +++ b/src/com/android/settings/SettingsHomepageActivity.java @@ -0,0 +1,61 @@ +/* + * 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; + +import android.app.Activity; +import android.app.Fragment; +import android.app.FragmentManager; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.util.FeatureFlagUtils; + +import com.android.settings.core.FeatureFlags; +import com.android.settings.homepage.HomepageFragment; +import com.android.settingslib.drawer.SettingsDrawerActivity; + +public class SettingsHomepageActivity extends SettingsDrawerActivity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + if (!isDynamicHomepageEnabled(this)) { + final Intent settings = new Intent(); + settings.setAction("android.settings.SETTINGS"); + startActivity(settings); + finish(); + } + setContentView(R.layout.settings_homepage); + switchToFragment(this, R.id.main_content, HomepageFragment.class.getName()); + } + + public static boolean isDynamicHomepageEnabled(Context context) { + return FeatureFlagUtils.isEnabled(context, FeatureFlags.DYNAMIC_HOMEPAGE); + } + + /** + * Switch to a specific Fragment + */ + public static void switchToFragment(Activity activity, int id, String fragmentName) { + final Fragment f = Fragment.instantiate(activity, fragmentName, null /* args */); + + FragmentManager manager = activity.getFragmentManager(); + manager.beginTransaction().replace(id, f).commitAllowingStateLoss(); + manager.executePendingTransactions(); + } +} \ No newline at end of file diff --git a/src/com/android/settings/core/FeatureFlags.java b/src/com/android/settings/core/FeatureFlags.java index 006bd70b5c4..08e4de54be5 100644 --- a/src/com/android/settings/core/FeatureFlags.java +++ b/src/com/android/settings/core/FeatureFlags.java @@ -23,4 +23,5 @@ public class FeatureFlags { public static final String BATTERY_DISPLAY_APP_LIST = "settings_battery_display_app_list"; public static final String BLUETOOTH_WHILE_DRIVING = "settings_bluetooth_while_driving"; public static final String AUDIO_SWITCHER_SETTINGS = "settings_audio_switcher"; + public static final String DYNAMIC_HOMEPAGE = "settings_dynamic_homepage"; } diff --git a/src/com/android/settings/homepage/HomepageFragment.java b/src/com/android/settings/homepage/HomepageFragment.java new file mode 100644 index 00000000000..3b0ca2b647f --- /dev/null +++ b/src/com/android/settings/homepage/HomepageFragment.java @@ -0,0 +1,150 @@ +/* + * 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.app.ActionBar; +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Toolbar; + +import androidx.annotation.NonNull; + +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; +import com.android.settings.R; +import com.android.settings.SettingsHomepageActivity; +import com.android.settings.Utils; +import com.android.settings.core.InstrumentedFragment; +import com.android.settings.dashboard.DashboardSummary; +import com.android.settings.overlay.FeatureFactory; +import com.android.settings.search.SearchFeatureProvider; + +import com.google.android.material.bottomappbar.BottomAppBar; +import com.google.android.material.bottomsheet.BottomSheetBehavior; +import com.google.android.material.floatingactionbutton.FloatingActionButton; + +public class HomepageFragment extends InstrumentedFragment { + + private static final String TAG = "HomepageFragment"; + + private FloatingActionButton mSearchButton; + private BottomSheetBehavior mBottomSheetBehavior; + private boolean mBottomFragmentLoaded = false; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + final View rootView = inflater.inflate(R.layout.dashboard, container, false); + return rootView; + } + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + setupBottomBar(); + setupSearchBar(); + } + + @Override + public int getMetricsCategory() { + return MetricsEvent.SETTINGS_HOMEPAGE; + } + + private void setupBottomBar() { + final Activity activity = getActivity(); + mSearchButton = (FloatingActionButton) activity.findViewById(R.id.search_fab); + + mSearchButton.setOnClickListener(v -> { + final Intent intent = SearchFeatureProvider.SEARCH_UI_INTENT; + intent.setPackage(FeatureFactory.getFactory(activity) + .getSearchFeatureProvider().getSettingsIntelligencePkgName()); + startActivityForResult(intent, 0 /* requestCode */); + }); + mBottomSheetBehavior = BottomSheetBehavior.from(activity.findViewById(R.id.bottom_sheet)); + final BottomAppBar bottomBar = (BottomAppBar) activity.findViewById(R.id.bar); + bottomBar.setOnClickListener(v -> { + mBottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED); + }); + + final int screenWidthpx = getResources().getDisplayMetrics().widthPixels; + final View searchbar = activity.findViewById(R.id.search_bar_container); + final View bottombar = activity.findViewById(R.id.bar); + + + mBottomSheetBehavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() { + @Override + public void onStateChanged(@NonNull View bottomSheet, int newState) { + if (!mBottomFragmentLoaded) { + SettingsHomepageActivity.switchToFragment(getActivity(), + R.id.bottom_sheet_fragment, DashboardSummary.class.getName()); + mBottomFragmentLoaded = true; + } + if (newState == BottomSheetBehavior.STATE_EXPANDED) { + bottombar.setVisibility(View.INVISIBLE); + searchbar.setVisibility(View.VISIBLE); + mSearchButton.setVisibility(View.GONE); + } else if (newState == BottomSheetBehavior.STATE_COLLAPSED) { + bottombar.setVisibility(View.VISIBLE); + searchbar.setVisibility(View.INVISIBLE); + mSearchButton.setVisibility(View.VISIBLE); + } else if (newState == BottomSheetBehavior.STATE_SETTLING) { + bottombar.setVisibility(View.VISIBLE); + searchbar.setVisibility(View.VISIBLE); + mSearchButton.setVisibility(View.VISIBLE); + } + } + + @Override + public void onSlide(@NonNull View bottomSheet, float slideOffset) { + bottombar.setAlpha(1 - slideOffset); + mSearchButton.setAlpha(1 - slideOffset); + searchbar.setAlpha(slideOffset); + searchbar.setPadding((int) (screenWidthpx * (1 - slideOffset)), 0, 0, 0); + } + }); + } + + //TODO(110767984), copied from settingsActivity. We have to merge them + private void setupSearchBar() { + final Activity activity = getActivity(); + final Toolbar toolbar = activity.findViewById(R.id.search_action_bar); + FeatureFactory.getFactory(activity).getSearchFeatureProvider() + .initSearchToolbar(activity, toolbar); + activity.setActionBar(toolbar); + + // Please forgive me for what I am about to do. + // + // Need to make the navigation icon non-clickable so that the entire card is clickable + // and goes to the search UI. Also set the background to null so there's no ripple. + final View navView = toolbar.getNavigationView(); + navView.setClickable(false); + navView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO); + navView.setBackground(null); + + final ActionBar actionBar = activity.getActionBar(); + if (actionBar != null) { + boolean deviceProvisioned = Utils.isDeviceProvisioned(activity); + actionBar.setDisplayHomeAsUpEnabled(deviceProvisioned); + actionBar.setHomeButtonEnabled(deviceProvisioned); + actionBar.setDisplayShowTitleEnabled(false); + } + } +}