Introduce SwitchBar widget

- SwitchBar is a LinearLayout that containts a TextView and a Switch and
is intended to replace all Switches that are put in the ActionBar as a
custom view
- use the new SwitchBar for WifiSetting only for now (a later CL will
take care of all the other Setting that are using a Switch in the
ActionBar)

Related to bug #14898161 On/Off switches must move down from Action Bar

Change-Id: I5e98dbe995bba8f440d08459e09ca3ac09d3464b
This commit is contained in:
Fabrice Di Meglio
2014-05-13 19:51:59 -07:00
parent a1ebae6f71
commit 4193776698
11 changed files with 301 additions and 80 deletions

View File

@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2014 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.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_enabled="false" android:state_checked="true">
<nine-patch android:src="@*android:drawable/switch_on_qntm_alpha"
android:tint="?android:attr/colorControlNormal"
android:alpha="?android:attr/disabledAlpha" />
</item>
<item android:state_enabled="false">
<nine-patch android:src="@*android:drawable/switch_off_qntm_alpha"
android:tint="?android:attr/colorControlNormal"
android:alpha="?android:attr/disabledAlpha" />
</item>
<item android:state_checked="true">
<nine-patch android:src="@*android:drawable/switch_on_qntm_alpha"
android:tint="@color/switch_accent_color" />
</item>
<item>
<nine-patch android:src="@*android:drawable/switch_off_qntm_alpha"
android:tint="?android:attr/colorControlNormal" />
</item>
</selector>

View File

@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2014 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.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="true">
<nine-patch android:src="@*android:drawable/switch_track_qntm_alpha"
android:tint="@color/switch_accent_color" />
</item>
<item>
<nine-patch android:src="@*android:drawable/switch_track_qntm_alpha"
android:tint="?android:attr/colorControlNormal" />
</item>
</selector>

View File

@@ -27,6 +27,12 @@
android:layout_height="match_parent"
android:layout_width="match_parent">
<com.android.settings.widget.SwitchBar android:id="@+id/switch_bar"
android:layout_height="?android:attr/actionBarSize"
android:layout_width="match_parent"
android:background="@color/switch_bar_background_color"
android:theme="@android:style/Theme.Quantum" />
<FrameLayout
android:id="@+id/prefs"
android:layout_width="match_parent"
@@ -49,6 +55,7 @@
android:layout_alignParentStart="true"
android:text="@*android:string/back_button_label"
/>
<LinearLayout
android:orientation="horizontal"
android:layout_width="wrap_content"

37
res/layout/switch_bar.xml Normal file
View File

@@ -0,0 +1,37 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
** Copyright 2014, 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.
*/
-->
<merge xmlns:android="http://schemas.android.com/apk/res/android" >
<TextView android:id="@+id/switch_text"
android:layout_height="wrap_content"
android:layout_width="0dp"
android:layout_weight="1"
android:paddingStart="32dp"
android:layout_gravity="center_vertical"
android:textAppearance="@style/TextAppearance.Switch"
android:textAlignment="viewStart" />
<Switch android:id="@+id/switch_widget"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:paddingEnd="32dp" />
</merge>

View File

@@ -62,4 +62,6 @@
<color name="actionbar_background_color">#ff263238</color>
<color name="dashboard_background_color">#ffe1e1e0</color>
<color name="switch_bar_background_color">#ff384248</color>
<color name="switch_accent_color">#ff7fcac3</color>
</resources>

View File

@@ -5247,4 +5247,8 @@
<!-- Full package name of OEM preferred device feedback reporter [DO NOT TRANSLATE] -->
<string name="oem_preferred_feedback_reporter" translatable="false"></string>
<!-- Switch On/Off -->
<string name="switch_on_text">On</string>
<string name="switch_off_text">Off</string>
</resources>

View File

@@ -261,4 +261,8 @@
<style name="ApnPreference">
<item name="android:layout">@layout/apn_preference_layout</item>
</style>
<style name="TextAppearance.Switch" parent="@android:style/TextAppearance.Quantum.Medium">
<item name="android:textSize">16sp</item>
</style>
</resources>

View File

@@ -102,6 +102,7 @@ import com.android.settings.tts.TextToSpeechSettings;
import com.android.settings.users.UserSettings;
import com.android.settings.vpn2.VpnSettings;
import com.android.settings.wfd.WifiDisplaySettings;
import com.android.settings.widget.SwitchBar;
import com.android.settings.wifi.AdvancedWifiSettings;
import com.android.settings.wifi.WifiSettings;
import com.android.settings.wifi.p2p.WifiP2pSettings;
@@ -300,8 +301,10 @@ public class SettingsActivity extends Activity
private final DynamicIndexableContentMonitor mDynamicIndexableContentMonitor =
new DynamicIndexableContentMonitor();
private Button mNextButton;
private ActionBar mActionBar;
private SwitchBar mSwitchBar;
private Button mNextButton;
private boolean mDisplayHomeAsUpEnabled;
private boolean mIsShowingDashboard;
@@ -330,6 +333,10 @@ public class SettingsActivity extends Activity
private boolean mNeedToRevertToInitialFragment = false;
public SwitchBar getSwitchBar() {
return mSwitchBar;
}
public AuthenticatorHelper getAuthenticatorHelper() {
return mAuthenticatorHelper;
}
@@ -389,11 +396,6 @@ public class SettingsActivity extends Activity
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Only show the Search menu on the main screen (Dashboard)
if (!mIsShowingDashboard) {
return true;
}
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.options_menu, menu);
@@ -505,6 +507,8 @@ public class SettingsActivity extends Activity
mActionBar.setDisplayHomeAsUpEnabled(mDisplayHomeAsUpEnabled);
mActionBar.setHomeButtonEnabled(mDisplayHomeAsUpEnabled);
mSwitchBar = (SwitchBar) findViewById(R.id.switch_bar);
// see if we should show Back/Next buttons
Intent intent = getIntent();
if (intent.getBooleanExtra(EXTRA_PREFS_SHOW_BUTTON_BAR, false)) {
@@ -1245,9 +1249,11 @@ public class SettingsActivity extends Activity
if (current != null && current instanceof SearchResultsSummary) {
mSearchResultsFragment = (SearchResultsSummary) current;
} else {
final boolean isShowingSwitchBar = mSwitchBar.isShowing();
String title = getString(R.string.search_results_title);
mSearchResultsFragment = (SearchResultsSummary) switchToFragment(
SearchResultsSummary.class.getName(), null, false, true, title, true);
SearchResultsSummary.class.getName(), null, false, true, title,
!isShowingSwitchBar);
}
mSearchResultsFragment.setSearchView(mSearchView);
mSearchMenuItemExpanded = true;

View File

@@ -0,0 +1,128 @@
/*
* Copyright (C) 2014 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.widget;
import android.content.Context;
import android.transition.TransitionManager;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CompoundButton;
import android.widget.LinearLayout;
import android.widget.Switch;
import android.widget.TextView;
import com.android.settings.R;
import java.util.ArrayList;
public class SwitchBar extends LinearLayout implements CompoundButton.OnCheckedChangeListener {
private Switch mSwitch;
private TextView mTextView;
private ArrayList<OnSwitchChangeListener> mSwitchChangeListeners =
new ArrayList<OnSwitchChangeListener>();
public static interface OnSwitchChangeListener {
/**
* Called when the checked state of the Switch has changed.
*
* @param switchView The Switch view whose state has changed.
* @param isChecked The new checked state of switchView.
*/
void onSwitchChanged(Switch switchView, boolean isChecked);
}
public SwitchBar(Context context) {
this(context, null);
}
public SwitchBar(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public SwitchBar(Context context, AttributeSet attrs, int defStyleAttr) {
this(context, attrs, defStyleAttr, 0);
}
public SwitchBar(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
LayoutInflater.from(context).inflate(R.layout.switch_bar, this);
mTextView = (TextView) findViewById(R.id.switch_text);
mTextView.setText(R.string.switch_off_text);
mSwitch = (Switch) findViewById(R.id.switch_widget);
mSwitch.setOnCheckedChangeListener(this);
addOnSwitchChangeListener(new OnSwitchChangeListener() {
@Override
public void onSwitchChanged(Switch switchView, boolean isChecked) {
mTextView.setText(isChecked ? R.string.switch_on_text : R.string.switch_off_text);
}
});
mSwitch.setTrackResource(R.drawable.switch_track);
mSwitch.setThumbResource(R.drawable.switch_inner);
// Default is hide
setVisibility(View.GONE);
}
public Switch getSwitch() {
return mSwitch;
}
public void show() {
TransitionManager.beginDelayedTransition((ViewGroup) getParent());
setVisibility(View.VISIBLE);
}
public void hide() {
TransitionManager.beginDelayedTransition((ViewGroup) getParent());
setVisibility(View.GONE);
}
public boolean isShowing() {
return (getVisibility() == View.VISIBLE);
}
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
final int count = mSwitchChangeListeners.size();
for (int n = 0; n < count; n++) {
mSwitchChangeListeners.get(n).onSwitchChanged(mSwitch,isChecked);
}
}
public void addOnSwitchChangeListener(OnSwitchChangeListener listener) {
if (mSwitchChangeListeners.contains(listener)) {
throw new IllegalStateException("Cannot add twice the same OnSwitchChangeListener");
}
mSwitchChangeListeners.add(listener);
}
public void removeOnSwitchChangeListener(OnSwitchChangeListener listener) {
if (!mSwitchChangeListeners.contains(listener)) {
throw new IllegalStateException("Cannot remove OnSwitchChangeListener");
}
mSwitchChangeListeners.remove(listener);
}
}

View File

@@ -34,12 +34,14 @@ import android.widget.Toast;
import com.android.settings.R;
import com.android.settings.WirelessSettings;
import com.android.settings.search.Index;
import com.android.settings.widget.SwitchBar;
import java.util.concurrent.atomic.AtomicBoolean;
public class WifiEnabler implements CompoundButton.OnCheckedChangeListener {
public class WifiEnabler implements SwitchBar.OnSwitchChangeListener {
private Context mContext;
private Switch mSwitch;
private SwitchBar mSwitchBar;
private AtomicBoolean mConnected = new AtomicBoolean(false);
private final WifiManager mWifiManager;
@@ -82,9 +84,10 @@ public class WifiEnabler implements CompoundButton.OnCheckedChangeListener {
}
};
public WifiEnabler(Context context, Switch switch_) {
public WifiEnabler(Context context, SwitchBar switchBar) {
mContext = context;
mSwitch = switch_;
mSwitchBar = switchBar;
mSwitch = switchBar.getSwitch();
mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
mIntentFilter = new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION);
@@ -97,53 +100,14 @@ public class WifiEnabler implements CompoundButton.OnCheckedChangeListener {
mContext = context;
// Wi-Fi state is sticky, so just let the receiver update UI
mContext.registerReceiver(mReceiver, mIntentFilter);
mSwitch.setOnCheckedChangeListener(this);
mSwitchBar.addOnSwitchChangeListener(this);
mSwitchBar.show();
}
public void pause() {
mContext.unregisterReceiver(mReceiver);
mSwitch.setOnCheckedChangeListener(null);
}
public void setSwitch(Switch switch_) {
if (mSwitch == switch_) return;
mSwitch.setOnCheckedChangeListener(null);
mSwitch = switch_;
mSwitch.setOnCheckedChangeListener(this);
final int wifiState = mWifiManager.getWifiState();
boolean isEnabled = wifiState == WifiManager.WIFI_STATE_ENABLED;
boolean isDisabled = wifiState == WifiManager.WIFI_STATE_DISABLED;
mSwitch.setChecked(isEnabled);
mSwitch.setEnabled(isEnabled || isDisabled);
}
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
//Do nothing if called as a result of a state machine event
if (mStateMachineEvent) {
return;
}
// Show toast message if Wi-Fi is not allowed in airplane mode
if (isChecked && !WirelessSettings.isRadioAllowed(mContext, Settings.Global.RADIO_WIFI)) {
Toast.makeText(mContext, R.string.wifi_in_airplane_mode, Toast.LENGTH_SHORT).show();
// Reset switch to off. No infinite check/listenenr loop.
buttonView.setChecked(false);
return;
}
// Disable tethering if enabling Wifi
int wifiApState = mWifiManager.getWifiApState();
if (isChecked && ((wifiApState == WifiManager.WIFI_AP_STATE_ENABLING) ||
(wifiApState == WifiManager.WIFI_AP_STATE_ENABLED))) {
mWifiManager.setWifiApEnabled(null, false);
}
mSwitch.setEnabled(false);
if (!mWifiManager.setWifiEnabled(isChecked)) {
// Error
mSwitch.setEnabled(true);
Toast.makeText(mContext, R.string.wifi_error, Toast.LENGTH_SHORT).show();
}
mSwitchBar.removeOnSwitchChangeListener(this);
mSwitchBar.hide();
}
private void handleWifiStateChanged(int state) {
@@ -203,4 +167,33 @@ public class WifiEnabler implements CompoundButton.OnCheckedChangeListener {
}
*/
}
@Override
public void onSwitchChanged(Switch switchView, boolean isChecked) {
//Do nothing if called as a result of a state machine event
if (mStateMachineEvent) {
return;
}
// Show toast message if Wi-Fi is not allowed in airplane mode
if (isChecked && !WirelessSettings.isRadioAllowed(mContext, Settings.Global.RADIO_WIFI)) {
Toast.makeText(mContext, R.string.wifi_in_airplane_mode, Toast.LENGTH_SHORT).show();
// Reset switch to off. No infinite check/listenenr loop.
switchView.setChecked(false);
return;
}
// Disable tethering if enabling Wifi
int wifiApState = mWifiManager.getWifiApState();
if (isChecked && ((wifiApState == WifiManager.WIFI_AP_STATE_ENABLING) ||
(wifiApState == WifiManager.WIFI_AP_STATE_ENABLED))) {
mWifiManager.setWifiApEnabled(null, false);
}
mSwitch.setEnabled(false);
if (!mWifiManager.setWifiEnabled(isChecked)) {
// Error
mSwitch.setEnabled(true);
Toast.makeText(mContext, R.string.wifi_error, Toast.LENGTH_SHORT).show();
}
}
}

View File

@@ -19,13 +19,13 @@ package com.android.settings.wifi;
import static android.net.wifi.WifiConfiguration.INVALID_NETWORK_ID;
import static android.os.UserManager.DISALLOW_CONFIG_WIFI;
import android.preference.PreferenceActivity;
import com.android.settings.R;
import com.android.settings.RestrictedSettingsFragment;
import com.android.settings.SettingsActivity;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settings.search.Indexable;
import com.android.settings.search.SearchIndexableRaw;
import com.android.settings.widget.SwitchBar;
import com.android.settings.wifi.p2p.WifiP2pSettings;
import android.app.ActionBar;
@@ -179,7 +179,7 @@ public class WifiSettings extends RestrictedSettingsFragment
// the action bar uses a different set of controls for Setup Wizard
private boolean mSetupWizardMode;
private Switch mSwitch;
private SwitchBar mSwitchBar;
/* End of "used in Wifi Setup context" */
@@ -413,32 +413,10 @@ public class WifiSettings extends RestrictedSettingsFragment
// On/off switch is hidden for Setup Wizard
if (!mSetupWizardMode) {
final Activity activity = getActivity();
final SettingsActivity activity = (SettingsActivity) getActivity();
mSwitch = new Switch(activity.getActionBar().getThemedContext());
final int padding = activity.getResources().getDimensionPixelSize(
R.dimen.action_bar_switch_padding);
mSwitch.setPaddingRelative(0, 0, padding, 0);
activity.getActionBar().setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM,
ActionBar.DISPLAY_SHOW_CUSTOM);
activity.getActionBar().setCustomView(mSwitch, new ActionBar.LayoutParams(
ActionBar.LayoutParams.WRAP_CONTENT,
ActionBar.LayoutParams.WRAP_CONTENT,
Gravity.CENTER_VERTICAL | Gravity.END));
mWifiEnabler = new WifiEnabler(activity, mSwitch);
}
}
@Override
public void onStop() {
super.onStop();
if (!mSetupWizardMode) {
final Activity activity = getActivity();
activity.getActionBar().setDisplayOptions(0, ActionBar.DISPLAY_SHOW_CUSTOM);
activity.getActionBar().setCustomView(null);
mSwitchBar = activity.getSwitchBar();
mWifiEnabler = new WifiEnabler(activity, mSwitchBar);
}
}