Launch channel settings as half sheet

If opening app has requested only a subset of fields

Test: manual - launch from an app, filtered and unfiltered, for
normal channels and conversations
Bug: 177246841
Change-Id: Ifd70478101d1ea1340d2ecc55033fab55e65ca92

Change-Id: I5194b959c82b2cfa7990c84285aaf69464cff3a8
This commit is contained in:
Julia Reynolds
2021-03-10 21:38:49 -05:00
parent 61aa289dac
commit efe26e2d44
10 changed files with 304 additions and 53 deletions

View File

@@ -68,12 +68,16 @@ public class ChannelNotificationSettings extends NotificationSettings {
if (mChannel != null && !TextUtils.isEmpty(mChannel.getConversationId())
&& !mChannel.isDemoted()) {
startActivity(new SubSettingLauncher(mContext)
Intent intent = new SubSettingLauncher(mContext)
.setDestination(ConversationNotificationSettings.class.getName())
.setArguments(getArguments())
.setExtras(getIntent() != null ? getIntent().getExtras(): null)
.setSourceMetricsCategory(SettingsEnums.NOTIFICATION_TOPIC_NOTIFICATION)
.toIntent());
.toIntent();
if (mPreferenceFilter != null) {
intent.setClass(mContext, ChannelPanelActivity.class);
}
startActivity(intent);
finish();
return;
}
@@ -84,6 +88,7 @@ public class ChannelNotificationSettings extends NotificationSettings {
controller.displayPreference(getPreferenceScreen());
}
updatePreferenceStates();
animatePanel();
}
@Override

View File

@@ -0,0 +1,111 @@
/*
* Copyright (C) 2021 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.notification.app;
import android.app.settings.SettingsEnums;
import android.content.Intent;
import android.content.res.Configuration;
import android.os.Bundle;
import android.provider.Settings;
import android.util.Log;
import android.view.Gravity;
import android.view.Window;
import android.view.WindowManager;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.FragmentActivity;
import androidx.fragment.app.FragmentManager;
import com.android.internal.annotations.VisibleForTesting;
import com.android.settings.R;
import com.android.settings.core.HideNonSystemOverlayMixin;
import com.android.settings.core.SubSettingLauncher;
/**
* Dialog Activity to host channel settings
*/
public class ChannelPanelActivity extends FragmentActivity {
private static final String TAG = "ChannelPanelActivity";
final Bundle mBundle = new Bundle();
NotificationSettings mPanelFragment;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (!getIntent().hasExtra(Settings.EXTRA_CHANNEL_FILTER_LIST)) {
launchFullSettings();
}
getApplicationContext().getTheme().rebase();
createOrUpdatePanel();
getLifecycle().addObserver(new HideNonSystemOverlayMixin(this));
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);
createOrUpdatePanel();
}
@Override
public void onConfigurationChanged(@NonNull Configuration newConfig) {
super.onConfigurationChanged(newConfig);
}
private void launchFullSettings() {
Bundle extras = getIntent().getExtras();
extras.remove(Settings.EXTRA_CHANNEL_FILTER_LIST);
startActivity(new SubSettingLauncher(this)
.setDestination(ChannelNotificationSettings.class.getName())
.setExtras(extras)
.setSourceMetricsCategory(SettingsEnums.NOTIFICATION_TOPIC_NOTIFICATION)
.toIntent());
finish();
}
private void createOrUpdatePanel() {
final Intent callingIntent = getIntent();
if (callingIntent == null) {
Log.e(TAG, "Null intent, closing Panel Activity");
finish();
return;
}
final FragmentManager fragmentManager = getSupportFragmentManager();
setContentView(R.layout.notification_channel_panel);
// Move the window to the bottom of screen, and make it take up the entire screen width.
final Window window = getWindow();
window.setGravity(Gravity.BOTTOM);
window.setLayout(WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.WRAP_CONTENT);
findViewById(R.id.done).setOnClickListener(v -> finish());
findViewById(R.id.see_more).setOnClickListener(v -> launchFullSettings());
mPanelFragment = callingIntent.hasExtra(Settings.EXTRA_CONVERSATION_ID)
? new ConversationNotificationSettings()
: new ChannelNotificationSettings();
mPanelFragment.setArguments(new Bundle(mBundle));
fragmentManager.beginTransaction().replace(
android.R.id.list_container, mPanelFragment).commit();
}
}

View File

@@ -93,6 +93,7 @@ public class ConversationHeaderPreferenceController extends NotificationPreferen
.done(activity, mContext);
pref.findViewById(R.id.entity_header).setVisibility(View.VISIBLE);
pref.findViewById(R.id.entity_header).setBackground(null);
}
}

View File

@@ -49,10 +49,11 @@ public class ConversationNotificationSettings extends NotificationSettings {
for (NotificationPreferenceController controller : mControllers) {
controller.onResume(mAppRow, mChannel, mChannelGroup, mConversationDrawable,
mConversationInfo, mSuspendedAppsAdmin, null);
mConversationInfo, mSuspendedAppsAdmin, mPreferenceFilter);
controller.displayPreference(getPreferenceScreen());
}
updatePreferenceStates();
animatePanel();
}
@Override

View File

@@ -92,6 +92,7 @@ public class HeaderPreferenceController extends NotificationPreferenceController
.setRecyclerView(mFragment.getListView(), mFragment.getSettingsLifecycle())
.done(activity, mContext);
pref.findViewById(R.id.entity_header).setVisibility(View.VISIBLE);
pref.findViewById(R.id.entity_header).setBackground(null);
}
}

View File

@@ -18,6 +18,9 @@ package com.android.settings.notification.app;
import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationChannelGroup;
@@ -39,8 +42,13 @@ import android.os.UserHandle;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.animation.DecelerateInterpolator;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.preference.PreferenceScreen;
import com.android.settings.R;
@@ -85,6 +93,20 @@ abstract public class NotificationSettings extends DashboardFragment {
protected Intent mIntent;
protected Bundle mArgs;
private ViewGroup mLayoutView;
private static final int DURATION_ANIMATE_PANEL_EXPAND_MS = 250;
private final ViewTreeObserver.OnGlobalLayoutListener mOnGlobalLayoutListener =
new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
animateIn();
if (mLayoutView != null) {
mLayoutView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
}
};
@Override
public void onAttach(Context context) {
super.onAttach(context);
@@ -187,6 +209,50 @@ abstract public class NotificationSettings extends DashboardFragment {
collectConfigActivities();
}
protected void animatePanel() {
if (mPreferenceFilter != null) {
mLayoutView = getActivity().findViewById(R.id.main_content);
mLayoutView.getViewTreeObserver().addOnGlobalLayoutListener(mOnGlobalLayoutListener);
}
}
/**
* Animate a Panel onto the screen.
* <p>
* Takes the entire panel and animates in from behind the navigation bar.
* <p>
* Relies on the Panel being having a fixed height to begin the animation.
*/
private void animateIn() {
final AnimatorSet animatorSet = buildAnimatorSet(mLayoutView,
mLayoutView.getHeight() /* startY */, 0.0f /* endY */,
0.0f /* startAlpha */, 1.0f /* endAlpha */,
DURATION_ANIMATE_PANEL_EXPAND_MS);
final ValueAnimator animator = new ValueAnimator();
animator.setFloatValues(0.0f, 1.0f);
animatorSet.play(animator);
animatorSet.start();
}
/**
* Build an {@link AnimatorSet} to animate the Panel, {@param parentView} in or out of the
* screen, based on the positional parameters {@param startY}, {@param endY}, the parameters
* for alpha changes {@param startAlpha}, {@param endAlpha}, and the {@param duration} in
* milliseconds.
*/
@NonNull
private static AnimatorSet buildAnimatorSet(@NonNull View targetView,
float startY, float endY,
float startAlpha, float endAlpha, int duration) {
final AnimatorSet animatorSet = new AnimatorSet();
animatorSet.setDuration(duration);
animatorSet.setInterpolator(new DecelerateInterpolator());
animatorSet.playTogether(
ObjectAnimator.ofFloat(targetView, View.TRANSLATION_Y, startY, endY),
ObjectAnimator.ofFloat(targetView, View.ALPHA, startAlpha, endAlpha));
return animatorSet;
}
private void loadPreferencesFilter() {
Intent intent = getActivity().getIntent();
mPreferenceFilter = intent != null