Merge "Add oobe dream settings activity"

This commit is contained in:
Lucas Silva
2022-02-02 19:26:13 +00:00
committed by Android (Google) Code Review
9 changed files with 283 additions and 35 deletions

View File

@@ -1,5 +1,4 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
package="com.android.settings" package="com.android.settings"
coreApp="true" coreApp="true"
android:sharedUserId="android.uid.system"> android:sharedUserId="android.uid.system">
@@ -2921,6 +2920,24 @@
android:value="true" /> android:value="true" />
</activity> </activity>
<activity android:name=".dream.DreamSetupActivity"
android:exported="true"
android:immersive="true"
android:theme="@style/SudThemeGlif.DayNight"
android:icon="@drawable/ic_settings_display">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="com.android.settings.suggested.category.SCREEN_SAVER"/>
</intent-filter>
<meta-data android:name="com.android.settings.is_supported"
android:resource="@bool/dream_setup_supported"/>
<meta-data android:name="com.android.settings.title"
android:resource="@string/dream_setup_title"/>
<meta-data android:name="com.android.settings.summary"
android:resource="@string/dream_setup_description"/>
<meta-data android:name="com.android.settings.icon_tintable" android:value="true"/>
</activity>
<activity <activity
android:name="Settings$UserSettingsActivity" android:name="Settings$UserSettingsActivity"
android:label="@string/user_settings_title" android:label="@string/user_settings_title"

View File

@@ -17,6 +17,6 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android" <selector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"> xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
<item android:state_activated="true" android:color="?androidprv:attr/colorSurfaceVariant"/> <item android:state_selected="true" android:color="?androidprv:attr/colorSurfaceVariant"/>
<item android:color="?androidprv:attr/colorSurfaceHighlight"/> <item android:color="?androidprv:attr/colorSurfaceHighlight"/>
</selector> </selector>

View File

@@ -0,0 +1,39 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2022 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.
-->
<com.google.android.setupdesign.GlifLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/setup_wizard_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:icon="@drawable/ic_settings_display"
app:sucHeaderText="@string/dream_setup_title"
app:sudDescriptionText="@string/dream_setup_description">
<RelativeLayout
android:id="@+id/dream_container"
style="@style/SudContentFrame"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/dream_setup_list"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</RelativeLayout>
</com.google.android.setupdesign.GlifLayout>

View File

@@ -590,4 +590,7 @@
Take the "Unrestricted data" page as the example, the visible app icons could be 15 Take the "Unrestricted data" page as the example, the visible app icons could be 15
on 6.4 inches screen size whether the font size and display size are both small. --> on 6.4 inches screen size whether the font size and display size are both small. -->
<integer name="config_num_visible_app_icons">20</integer> <integer name="config_num_visible_app_icons">20</integer>
<!-- Whether the dream setup activity should be enabled as part of setupwizard -->
<bool name="dream_setup_supported">false</bool>
</resources> </resources>

View File

@@ -13850,6 +13850,10 @@
<string name="dream_complications_picker_category">Choose more options</string> <string name="dream_complications_picker_category">Choose more options</string>
<!-- The title of the category to show for the screensaver miscellaneous settings [CHAR LIMIT=none] --> <!-- The title of the category to show for the screensaver miscellaneous settings [CHAR LIMIT=none] -->
<string name="dream_more_settings_category">More settings</string> <string name="dream_more_settings_category">More settings</string>
<!-- The title of the screen saver setup page [CHAR LIMIT=none] -->
<string name="dream_setup_title">Customize your screen saver</string>
<!-- The description of the screen saver setup page [CHAR LIMIT=none] -->
<string name="dream_setup_description">Choose what youll see on your screen when your device is not in use.</string>
<!-- Button to customize the screensaver [CHAR LIMIT=20] --> <!-- Button to customize the screensaver [CHAR LIMIT=20] -->
<string name="customize_button_title">Customize</string> <string name="customize_button_title">Customize</string>

View File

@@ -39,11 +39,12 @@ import java.util.List;
*/ */
class DreamAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { class DreamAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private final List<IDreamItem> mItemList; private final List<IDreamItem> mItemList;
private int mLastSelectedPos = -1;
/** /**
* View holder for each {@link IDreamItem}. * View holder for each {@link IDreamItem}.
*/ */
private static class DreamViewHolder extends RecyclerView.ViewHolder { private class DreamViewHolder extends RecyclerView.ViewHolder {
private final ImageView mIconView; private final ImageView mIconView;
private final TextView mTitleView; private final TextView mTitleView;
private final ImageView mPreviewView; private final ImageView mPreviewView;
@@ -62,7 +63,7 @@ class DreamAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
/** /**
* Bind the view at the given position, populating the view with the provided data. * Bind the view at the given position, populating the view with the provided data.
*/ */
public void bindView(IDreamItem item) { public void bindView(IDreamItem item, int position) {
mTitleView.setText(item.getTitle()); mTitleView.setText(item.getTitle());
final Drawable previewImage = item.getPreviewImage(); final Drawable previewImage = item.getPreviewImage();
@@ -73,20 +74,32 @@ class DreamAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
mPreviewView.setVisibility(View.GONE); mPreviewView.setVisibility(View.GONE);
} }
final Drawable icon = item.getIcon(); final Drawable icon = item.isActive()
? mContext.getDrawable(R.drawable.ic_dream_check_circle)
: item.getIcon();
if (icon instanceof VectorDrawable) { if (icon instanceof VectorDrawable) {
icon.setTint(Utils.getColorAttrDefaultColor(mContext, icon.setTint(Utils.getColorAttrDefaultColor(mContext,
com.android.internal.R.attr.colorAccentPrimaryVariant)); com.android.internal.R.attr.colorAccentPrimaryVariant));
} }
mIconView.setImageDrawable(icon); mIconView.setImageDrawable(icon);
if (item.allowCustomization()) {
mCustomizeButton.setVisibility(View.VISIBLE); if (item.isActive()) {
mCustomizeButton.setOnClickListener(v -> item.onCustomizeClicked()); mLastSelectedPos = position;
itemView.setSelected(true);
} else { } else {
mCustomizeButton.setVisibility(View.GONE); itemView.setSelected(false);
} }
itemView.setOnClickListener(v -> item.onItemClicked());
itemView.setActivated(item.isActive()); mCustomizeButton.setOnClickListener(v -> item.onCustomizeClicked());
mCustomizeButton.setVisibility(item.allowCustomization() ? View.VISIBLE : View.GONE);
itemView.setOnClickListener(v -> {
item.onItemClicked();
if (mLastSelectedPos > -1 && mLastSelectedPos != position) {
notifyItemChanged(mLastSelectedPos);
}
notifyItemChanged(position);
});
} }
} }
@@ -104,7 +117,7 @@ class DreamAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
@Override @Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int i) { public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int i) {
((DreamViewHolder) viewHolder).bindView(mItemList.get(i)); ((DreamViewHolder) viewHolder).bindView(mItemList.get(i), i);
} }
@Override @Override

View File

@@ -37,9 +37,7 @@ public class DreamComplicationPickerController extends BasePreferenceController
private static final String KEY = "dream_complication_picker"; private static final String KEY = "dream_complication_picker";
private final DreamBackend mBackend; private final DreamBackend mBackend;
private final Drawable mEnabledDrawable;
private final Set<Integer> mSupportedComplications; private final Set<Integer> mSupportedComplications;
private DreamAdapter mAdapter;
private class ComplicationItem implements IDreamItem { private class ComplicationItem implements IDreamItem {
private final int mComplicationType; private final int mComplicationType;
@@ -58,14 +56,13 @@ public class DreamComplicationPickerController extends BasePreferenceController
@Override @Override
public Drawable getIcon() { public Drawable getIcon() {
// TODO(b/215703483): add icon for each complication // TODO(b/215703483): add icon for each complication
return mEnabled ? mEnabledDrawable : null; return null;
} }
@Override @Override
public void onItemClicked() { public void onItemClicked() {
mEnabled = !mEnabled; mEnabled = !mEnabled;
mBackend.setComplicationEnabled(mComplicationType, mEnabled); mBackend.setComplicationEnabled(mComplicationType, mEnabled);
mAdapter.notifyDataSetChanged();
} }
@Override @Override
@@ -84,7 +81,6 @@ public class DreamComplicationPickerController extends BasePreferenceController
super(context, KEY); super(context, KEY);
mBackend = DreamBackend.getInstance(context); mBackend = DreamBackend.getInstance(context);
mSupportedComplications = mBackend.getSupportedComplications(); mSupportedComplications = mBackend.getSupportedComplications();
mEnabledDrawable = context.getDrawable(R.drawable.ic_dream_check_circle);
} }
@Override @Override
@@ -102,7 +98,7 @@ public class DreamComplicationPickerController extends BasePreferenceController
public void displayPreference(PreferenceScreen screen) { public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen); super.displayPreference(screen);
mAdapter = new DreamAdapter(mSupportedComplications.stream() DreamAdapter adapter = new DreamAdapter(mSupportedComplications.stream()
.map(ComplicationItem::new) .map(ComplicationItem::new)
.collect(Collectors.toList())); .collect(Collectors.toList()));
@@ -110,7 +106,8 @@ public class DreamComplicationPickerController extends BasePreferenceController
if (pref != null) { if (pref != null) {
final RecyclerView recyclerView = pref.findViewById(R.id.dream_list); final RecyclerView recyclerView = pref.findViewById(R.id.dream_list);
recyclerView.setLayoutManager(new AutoFitGridLayoutManager(mContext)); recyclerView.setLayoutManager(new AutoFitGridLayoutManager(mContext));
recyclerView.setAdapter(mAdapter); recyclerView.setHasFixedSize(true);
recyclerView.setAdapter(adapter);
} }
} }
} }

View File

@@ -31,6 +31,7 @@ import com.android.settings.core.BasePreferenceController;
import com.android.settings.overlay.FeatureFactory; import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.dream.DreamBackend; import com.android.settingslib.dream.DreamBackend;
import com.android.settingslib.dream.DreamBackend.DreamInfo;
import com.android.settingslib.widget.LayoutPreference; import com.android.settingslib.widget.LayoutPreference;
import java.util.List; import java.util.List;
@@ -44,11 +45,10 @@ public class DreamPickerController extends BasePreferenceController {
private final DreamBackend mBackend; private final DreamBackend mBackend;
private final MetricsFeatureProvider mMetricsFeatureProvider; private final MetricsFeatureProvider mMetricsFeatureProvider;
private final List<DreamBackend.DreamInfo> mDreamInfos; private final List<DreamInfo> mDreamInfos;
private final Drawable mActiveDrawable;
private Button mPreviewButton; private Button mPreviewButton;
@Nullable @Nullable
private DreamBackend.DreamInfo mActiveDream; private DreamInfo mActiveDream;
private DreamAdapter mAdapter; private DreamAdapter mAdapter;
public DreamPickerController(Context context) { public DreamPickerController(Context context) {
@@ -59,7 +59,7 @@ public class DreamPickerController extends BasePreferenceController {
super(context, KEY); super(context, KEY);
mBackend = backend; mBackend = backend;
mDreamInfos = mBackend.getDreamInfos(); mDreamInfos = mBackend.getDreamInfos();
mActiveDrawable = context.getDrawable(R.drawable.ic_dream_check_circle); mActiveDream = getActiveDreamInfo(mDreamInfos);
mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider(); mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider();
} }
@@ -77,8 +77,6 @@ public class DreamPickerController extends BasePreferenceController {
public void updateState(Preference preference) { public void updateState(Preference preference) {
super.updateState(preference); super.updateState(preference);
mActiveDream = getActiveDreamInfo();
mAdapter = new DreamAdapter(mDreamInfos.stream() mAdapter = new DreamAdapter(mDreamInfos.stream()
.map(DreamItem::new) .map(DreamItem::new)
.collect(Collectors.toList())); .collect(Collectors.toList()));
@@ -86,6 +84,7 @@ public class DreamPickerController extends BasePreferenceController {
final RecyclerView recyclerView = final RecyclerView recyclerView =
((LayoutPreference) preference).findViewById(R.id.dream_list); ((LayoutPreference) preference).findViewById(R.id.dream_list);
recyclerView.setLayoutManager(new AutoFitGridLayoutManager(mContext)); recyclerView.setLayoutManager(new AutoFitGridLayoutManager(mContext));
recyclerView.setHasFixedSize(true);
recyclerView.setAdapter(mAdapter); recyclerView.setAdapter(mAdapter);
mPreviewButton = ((LayoutPreference) preference).findViewById(R.id.preview_button); mPreviewButton = ((LayoutPreference) preference).findViewById(R.id.preview_button);
@@ -101,8 +100,8 @@ public class DreamPickerController extends BasePreferenceController {
} }
@Nullable @Nullable
private DreamBackend.DreamInfo getActiveDreamInfo() { private static DreamInfo getActiveDreamInfo(List<DreamInfo> dreamInfos) {
return mDreamInfos return dreamInfos
.stream() .stream()
.filter(d -> d.isActive) .filter(d -> d.isActive)
.findFirst() .findFirst()
@@ -110,9 +109,9 @@ public class DreamPickerController extends BasePreferenceController {
} }
private class DreamItem implements IDreamItem { private class DreamItem implements IDreamItem {
DreamBackend.DreamInfo mDreamInfo; DreamInfo mDreamInfo;
DreamItem(DreamBackend.DreamInfo dreamInfo) { DreamItem(DreamInfo dreamInfo) {
mDreamInfo = dreamInfo; mDreamInfo = dreamInfo;
} }
@@ -123,14 +122,13 @@ public class DreamPickerController extends BasePreferenceController {
@Override @Override
public Drawable getIcon() { public Drawable getIcon() {
return isActive() ? mActiveDrawable : mDreamInfo.icon; return mDreamInfo.icon;
} }
@Override @Override
public void onItemClicked() { public void onItemClicked() {
mActiveDream = mDreamInfo; mActiveDream = mDreamInfo;
mBackend.setActiveDream(mDreamInfo.componentName); mBackend.setActiveDream(mDreamInfo.componentName);
mAdapter.notifyDataSetChanged();
updatePreviewButtonState(); updatePreviewButtonState();
mMetricsFeatureProvider.action( mMetricsFeatureProvider.action(
mContext, mContext,

View File

@@ -0,0 +1,177 @@
/*
* Copyright (C) 2022 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.dream;
import android.app.settings.SettingsEnums;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.recyclerview.widget.RecyclerView;
import com.android.settings.R;
import com.android.settings.SettingsActivity;
import com.android.settings.SettingsPreferenceFragment;
import com.android.settingslib.dream.DreamBackend;
import com.google.android.setupcompat.template.FooterBarMixin;
import com.google.android.setupcompat.template.FooterButton;
import com.google.android.setupcompat.util.WizardManagerHelper;
import com.google.android.setupdesign.GlifLayout;
import com.google.android.setupdesign.util.ThemeHelper;
import com.google.android.setupdesign.util.ThemeResolver;
import java.util.List;
import java.util.stream.Collectors;
/**
* The setup activity for dreams which is displayed during setup wizard.
*/
public class DreamSetupActivity extends SettingsActivity {
@Override
public Intent getIntent() {
Intent modIntent = new Intent(super.getIntent());
modIntent.putExtra(EXTRA_SHOW_FRAGMENT, DreamSetupFragment.class.getName());
return modIntent;
}
@Override
protected boolean isValidFragment(String fragmentName) {
return DreamSetupFragment.class.getName().equals(fragmentName);
}
@Override
protected void onCreate(Bundle savedInstance) {
setTheme(ThemeResolver.getDefault().resolve(getIntent()));
ThemeHelper.trySetDynamicColor(this);
super.onCreate(savedInstance);
}
@Override
protected boolean isToolbarEnabled() {
return false;
}
/**
* Fragment used to control the active dream.
*/
public static class DreamSetupFragment extends SettingsPreferenceFragment {
private DreamBackend mBackend;
private DreamBackend.DreamInfo mActiveDream;
private FooterButton mFooterButton;
@Override
public int getMetricsCategory() {
return SettingsEnums.DREAM;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.dream_setup_layout, container, false);
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mBackend = DreamBackend.getInstance(getContext());
final List<DreamBackend.DreamInfo> dreamInfos = mBackend.getDreamInfos();
mActiveDream = dreamInfos.stream().filter(d -> d.isActive).findFirst().orElse(null);
DreamAdapter dreamAdapter = new DreamAdapter(dreamInfos.stream()
.map(DreamItem::new)
.collect(Collectors.toList()));
final RecyclerView recyclerView = view.findViewById(R.id.dream_setup_list);
recyclerView.setLayoutManager(new AutoFitGridLayoutManager(getContext()));
recyclerView.setHasFixedSize(true);
recyclerView.setAdapter(dreamAdapter);
final GlifLayout layout = view.findViewById(R.id.setup_wizard_layout);
final FooterBarMixin mixin = layout.getMixin(FooterBarMixin.class);
mFooterButton = new FooterButton.Builder(getContext())
.setListener(this::onPrimaryButtonClicked)
.setButtonType(FooterButton.ButtonType.NEXT)
.setTheme(R.style.SudGlifButton_Primary)
.build();
updateFooterButtonText();
mixin.setPrimaryButton(mFooterButton);
}
private void updateFooterButtonText() {
final int res = canCustomizeDream() ? R.string.wizard_next : R.string.wizard_finish;
mFooterButton.setText(getContext().getString(res));
}
private boolean canCustomizeDream() {
return mActiveDream != null && mActiveDream.settingsComponentName != null;
}
private void onPrimaryButtonClicked(View view) {
if (canCustomizeDream()) {
final Intent intent = new Intent().setComponent(mActiveDream.settingsComponentName);
WizardManagerHelper.copyWizardManagerExtras(getIntent(), intent);
startActivity(intent);
}
// Use RESULT_CANCELED here so that the user may go back and change this if they wish.
setResult(RESULT_CANCELED);
finish();
}
private class DreamItem implements IDreamItem {
private final DreamBackend.DreamInfo mDreamInfo;
private DreamItem(DreamBackend.DreamInfo dreamInfo) {
mDreamInfo = dreamInfo;
}
@Override
public CharSequence getTitle() {
return mDreamInfo.caption;
}
@Override
public Drawable getIcon() {
return mDreamInfo.icon;
}
@Override
public void onItemClicked() {
mActiveDream = mDreamInfo;
mBackend.setActiveDream(mDreamInfo.componentName);
updateFooterButtonText();
}
@Override
public Drawable getPreviewImage() {
return mDreamInfo.previewImage;
}
@Override
public boolean isActive() {
if (mActiveDream == null) {
return false;
}
return mDreamInfo.componentName.equals(mActiveDream.componentName);
}
}
}
}