blob: 5ecb18650060708f71bb325409711cf3417bf4c2 [file] [log] [blame]
/*
* 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.launcher3.config;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Process;
import android.text.Html;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;
import com.android.launcher3.R;
import com.android.launcher3.config.BaseFlags.TogglableFlag;
import androidx.preference.PreferenceDataStore;
import androidx.preference.PreferenceFragment;
import androidx.preference.PreferenceGroup;
import androidx.preference.SwitchPreference;
/**
* Dev-build only UI allowing developers to toggle flag settings. See {@link FeatureFlags}.
*/
public final class FlagTogglerPrefUi {
private static final String TAG = "FlagTogglerPrefFrag";
private final PreferenceFragment mFragment;
private final Context mContext;
private final SharedPreferences mSharedPreferences;
private final PreferenceDataStore mDataStore = new PreferenceDataStore() {
@Override
public void putBoolean(String key, boolean value) {
for (TogglableFlag flag : FeatureFlags.getTogglableFlags()) {
if (flag.getKey().equals(key)) {
boolean prevValue = flag.get();
flag.updateStorage(mContext, value);
updateMenu();
if (flag.get() != prevValue) {
Toast.makeText(mContext, "Flag applied", Toast.LENGTH_SHORT).show();
}
}
}
}
@Override
public boolean getBoolean(String key, boolean defaultValue) {
for (TogglableFlag flag : FeatureFlags.getTogglableFlags()) {
if (flag.getKey().equals(key)) {
return flag.getFromStorage(mContext, defaultValue);
}
}
return defaultValue;
}
};
public FlagTogglerPrefUi(PreferenceFragment fragment) {
mFragment = fragment;
mContext = fragment.getActivity();
mSharedPreferences = mContext.getSharedPreferences(
FeatureFlags.FLAGS_PREF_NAME, Context.MODE_PRIVATE);
}
public void applyTo(PreferenceGroup parent) {
// For flag overrides we only want to store when the engineer chose to override the
// flag with a different value than the default. That way, when we flip flags in
// future, engineers will pick up the new value immediately. To accomplish this, we use a
// custom preference data store.
for (TogglableFlag flag : FeatureFlags.getTogglableFlags()) {
SwitchPreference switchPreference = new SwitchPreference(mContext);
switchPreference.setKey(flag.getKey());
switchPreference.setDefaultValue(flag.getDefaultValue());
switchPreference.setChecked(getFlagStateFromSharedPrefs(flag));
switchPreference.setTitle(flag.getKey());
updateSummary(switchPreference, flag);
switchPreference.setPreferenceDataStore(mDataStore);
parent.addPreference(switchPreference);
}
updateMenu();
}
/**
* Updates the summary to show the description and whether the flag overrides the default value.
*/
private void updateSummary(SwitchPreference switchPreference, TogglableFlag flag) {
String onWarning = flag.getDefaultValue() ? "" : "<b>OVERRIDDEN</b><br>";
String offWarning = flag.getDefaultValue() ? "<b>OVERRIDDEN</b><br>" : "";
switchPreference.setSummaryOn(Html.fromHtml(onWarning + flag.getDescription()));
switchPreference.setSummaryOff(Html.fromHtml(offWarning + flag.getDescription()));
}
private void updateMenu() {
mFragment.setHasOptionsMenu(anyChanged());
mFragment.getActivity().invalidateOptionsMenu();
}
public void onCreateOptionsMenu(Menu menu) {
if (anyChanged()) {
menu.add(0, R.id.menu_apply_flags, 0, "Apply")
.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
}
}
public void onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.menu_apply_flags) {
mSharedPreferences.edit().commit();
Log.e(TAG,
"Killing launcher process " + Process.myPid() + " to apply new flag values");
System.exit(0);
}
}
public void onStop() {
if (anyChanged()) {
Toast.makeText(mContext, "Flag won't be applied until you restart launcher",
Toast.LENGTH_LONG).show();
}
}
private boolean getFlagStateFromSharedPrefs(TogglableFlag flag) {
return mDataStore.getBoolean(flag.getKey(), flag.getDefaultValue());
}
private boolean anyChanged() {
for (TogglableFlag flag : FeatureFlags.getTogglableFlags()) {
if (getFlagStateFromSharedPrefs(flag) != flag.get()) {
return true;
}
}
return false;
}
}