blob: 8b7f53fa5a3f17bd0dc8e9d7c8b2080113ef8ad5 [file] [log] [blame]
/*
* Copyright (C) 2015 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.systemui.qs.tiles;
import static android.provider.Settings.Global.ZEN_MODE_ALARMS;
import static android.provider.Settings.Global.ZEN_MODE_OFF;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.net.Uri;
import android.os.Handler;
import android.os.Looper;
import android.os.UserManager;
import android.provider.Settings;
import android.provider.Settings.Global;
import android.service.notification.ZenModeConfig;
import android.service.quicksettings.Tile;
import android.text.TextUtils;
import android.view.View;
import android.widget.Switch;
import androidx.annotation.Nullable;
import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settingslib.notification.EnableZenModeDialog;
import com.android.systemui.Prefs;
import com.android.systemui.R;
import com.android.systemui.animation.DialogCuj;
import com.android.systemui.animation.DialogLaunchAnimator;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.qs.QSTile.BooleanState;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.qs.QSHost;
import com.android.systemui.qs.SettingObserver;
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.qs.tileimpl.QSTileImpl;
import com.android.systemui.qs.tiles.dialog.QSZenModeDialogMetricsLogger;
import com.android.systemui.statusbar.phone.SystemUIDialog;
import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.util.settings.SecureSettings;
import javax.inject.Inject;
/** Quick settings tile: Do not disturb **/
public class DndTile extends QSTileImpl<BooleanState> {
private static final Intent ZEN_SETTINGS =
new Intent(Settings.ACTION_ZEN_MODE_SETTINGS);
private static final Intent ZEN_PRIORITY_SETTINGS =
new Intent(Settings.ACTION_ZEN_MODE_PRIORITY_SETTINGS);
private static final String INTERACTION_JANK_TAG = "start_zen_mode";
private final ZenModeController mController;
private final SharedPreferences mSharedPreferences;
private final SettingObserver mSettingZenDuration;
private final DialogLaunchAnimator mDialogLaunchAnimator;
private final QSZenModeDialogMetricsLogger mQSZenDialogMetricsLogger;
private boolean mListening;
@Inject
public DndTile(
QSHost host,
@Background Looper backgroundLooper,
@Main Handler mainHandler,
FalsingManager falsingManager,
MetricsLogger metricsLogger,
StatusBarStateController statusBarStateController,
ActivityStarter activityStarter,
QSLogger qsLogger,
ZenModeController zenModeController,
@Main SharedPreferences sharedPreferences,
SecureSettings secureSettings,
DialogLaunchAnimator dialogLaunchAnimator
) {
super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
statusBarStateController, activityStarter, qsLogger);
mController = zenModeController;
mSharedPreferences = sharedPreferences;
mController.observe(getLifecycle(), mZenCallback);
mDialogLaunchAnimator = dialogLaunchAnimator;
mSettingZenDuration = new SettingObserver(secureSettings, mUiHandler,
Settings.Secure.ZEN_DURATION, getHost().getUserId()) {
@Override
protected void handleValueChanged(int value, boolean observedChange) {
refreshState();
}
};
mQSZenDialogMetricsLogger = new QSZenModeDialogMetricsLogger(mContext);
}
public static void setVisible(Context context, boolean visible) {
Prefs.putBoolean(context, Prefs.Key.DND_TILE_VISIBLE, visible);
}
public static boolean isVisible(SharedPreferences prefs) {
return prefs.getBoolean(Prefs.Key.DND_TILE_VISIBLE, false /* defaultValue */);
}
public static void setCombinedIcon(Context context, boolean combined) {
Prefs.putBoolean(context, Prefs.Key.DND_TILE_COMBINED_ICON, combined);
}
public static boolean isCombinedIcon(SharedPreferences sharedPreferences) {
return sharedPreferences.getBoolean(Prefs.Key.DND_TILE_COMBINED_ICON,
false /* defaultValue */);
}
@Override
public BooleanState newTileState() {
return new BooleanState();
}
@Override
public Intent getLongClickIntent() {
return ZEN_SETTINGS;
}
@Override
protected void handleClick(@Nullable View view) {
// Zen is currently on
if (mState.value) {
mController.setZen(ZEN_MODE_OFF, null, TAG);
} else {
enableZenMode(view);
}
}
@Override
protected void handleUserSwitch(int newUserId) {
super.handleUserSwitch(newUserId);
mSettingZenDuration.setUserId(newUserId);
}
private void enableZenMode(@Nullable View view) {
int zenDuration = mSettingZenDuration.getValue();
boolean showOnboarding = Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.SHOW_ZEN_UPGRADE_NOTIFICATION, 0) != 0
&& Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.ZEN_SETTINGS_UPDATED, 0) != 1;
if (showOnboarding) {
// don't show on-boarding again or notification ever
Settings.Secure.putInt(mContext.getContentResolver(),
Settings.Secure.SHOW_ZEN_UPGRADE_NOTIFICATION, 0);
// turn on DND
mController.setZen(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS, null, TAG);
// show on-boarding screen
Intent intent = new Intent(Settings.ZEN_MODE_ONBOARDING);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
mActivityStarter.postStartActivityDismissingKeyguard(intent, 0);
} else {
switch (zenDuration) {
case Settings.Secure.ZEN_DURATION_PROMPT:
mUiHandler.post(() -> {
Dialog dialog = makeZenModeDialog();
if (view != null) {
mDialogLaunchAnimator.showFromView(dialog, view, new DialogCuj(
InteractionJankMonitor.CUJ_SHADE_DIALOG_OPEN,
INTERACTION_JANK_TAG),
/* animateBackgroundBoundsChange= */ false);
} else {
dialog.show();
}
});
break;
case Settings.Secure.ZEN_DURATION_FOREVER:
mController.setZen(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS, null, TAG);
break;
default:
Uri conditionId = ZenModeConfig.toTimeCondition(mContext, zenDuration,
mHost.getUserId(), true).id;
mController.setZen(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS,
conditionId, TAG);
}
}
}
private Dialog makeZenModeDialog() {
AlertDialog dialog = new EnableZenModeDialog(mContext, R.style.Theme_SystemUI_Dialog,
true /* cancelIsNeutral */,
mQSZenDialogMetricsLogger).createDialog();
SystemUIDialog.applyFlags(dialog);
SystemUIDialog.setShowForAllUsers(dialog, true);
SystemUIDialog.registerDismissListener(dialog);
SystemUIDialog.setDialogSize(dialog);
return dialog;
}
@Override
protected void handleSecondaryClick(@Nullable View view) {
handleLongClick(view);
}
@Override
public CharSequence getTileLabel() {
return mContext.getString(R.string.quick_settings_dnd_label);
}
@Override
protected void handleUpdateState(BooleanState state, Object arg) {
if (mController == null) return;
final int zen = arg instanceof Integer ? (Integer) arg : mController.getZen();
final boolean newValue = zen != ZEN_MODE_OFF;
state.dualTarget = true;
state.value = newValue;
state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
state.icon = ResourceIcon.get(state.value
? R.drawable.qs_dnd_icon_on
: R.drawable.qs_dnd_icon_off);
state.label = getTileLabel();
state.secondaryLabel = TextUtils.emptyIfNull(ZenModeConfig.getDescription(mContext,
zen != Global.ZEN_MODE_OFF, mController.getConfig(), false));
checkIfRestrictionEnforcedByAdminOnly(state, UserManager.DISALLOW_ADJUST_VOLUME);
// Keeping the secondaryLabel in contentDescription instead of stateDescription is easier
// to understand.
switch (zen) {
case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS:
state.contentDescription =
mContext.getString(R.string.accessibility_quick_settings_dnd) + ", "
+ state.secondaryLabel;
break;
case Global.ZEN_MODE_NO_INTERRUPTIONS:
state.contentDescription =
mContext.getString(R.string.accessibility_quick_settings_dnd) + ", " +
mContext.getString(R.string.accessibility_quick_settings_dnd_none_on)
+ ", " + state.secondaryLabel;
break;
case ZEN_MODE_ALARMS:
state.contentDescription =
mContext.getString(R.string.accessibility_quick_settings_dnd) + ", " +
mContext.getString(R.string.accessibility_quick_settings_dnd_alarms_on)
+ ", " + state.secondaryLabel;
break;
default:
state.contentDescription = mContext.getString(
R.string.accessibility_quick_settings_dnd);
break;
}
state.dualLabelContentDescription = mContext.getResources().getString(
R.string.accessibility_quick_settings_open_settings, getTileLabel());
state.expandedAccessibilityClassName = Switch.class.getName();
state.forceExpandIcon =
mSettingZenDuration.getValue() == Settings.Secure.ZEN_DURATION_PROMPT;
}
@Override
public int getMetricsCategory() {
return MetricsEvent.QS_DND;
}
@Override
public void handleSetListening(boolean listening) {
super.handleSetListening(listening);
if (mListening == listening) return;
mListening = listening;
if (mListening) {
Prefs.registerListener(mContext, mPrefListener);
} else {
Prefs.unregisterListener(mContext, mPrefListener);
}
mSettingZenDuration.setListening(listening);
}
@Override
protected void handleDestroy() {
super.handleDestroy();
mSettingZenDuration.setListening(false);
}
@Override
public boolean isAvailable() {
return isVisible(mSharedPreferences);
}
private final OnSharedPreferenceChangeListener mPrefListener
= new OnSharedPreferenceChangeListener() {
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
@Prefs.Key String key) {
if (Prefs.Key.DND_TILE_COMBINED_ICON.equals(key) ||
Prefs.Key.DND_TILE_VISIBLE.equals(key)) {
refreshState();
}
}
};
private final ZenModeController.Callback mZenCallback = new ZenModeController.Callback() {
public void onZenChanged(int zen) {
refreshState(zen);
}
};
}