Tuner: Let Status bar be tuned

Also fix a crash in the QSTuner

Bug: 21192440
Change-Id: Ideb8e34b93a4b456d758266dfc06545e7f7ab109
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index d96ed96..6af69d2 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1034,6 +1034,21 @@
     <!-- Name of quick settings -->
     <string name="quick_settings">Quick Settings</string>
 
+    <!-- Name of status bar -->
+    <string name="status_bar">Status bar</string>
+
+    <!-- Name of the ethernet status bar icon. -->
+    <string name="status_bar_ethernet">Ethernet</string>
+
+    <!-- Name of the alarm status bar icon. -->
+    <string name="status_bar_alarm">Alarm</string>
+
+    <!-- Name of the work status bar icon. -->
+    <string name="status_bar_work">Work profile</string>
+
+    <!-- Name of the airplane status bar icon. -->
+    <string name="status_bar_airplane">Airplane mode</string>
+
     <!-- Description for adding  a quick settings tile -->
     <string name="add_tile">Add tile</string>
 
diff --git a/packages/SystemUI/res/xml/tuner_prefs.xml b/packages/SystemUI/res/xml/tuner_prefs.xml
index 135cc82..4e9a407 100644
--- a/packages/SystemUI/res/xml/tuner_prefs.xml
+++ b/packages/SystemUI/res/xml/tuner_prefs.xml
@@ -15,16 +15,61 @@
 -->
 
 <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
-        android:title="@string/system_ui_tuner">
+    android:title="@string/system_ui_tuner">
 
-        <Preference
-            android:key="qs_tuner"
-            android:title="@string/quick_settings" />
+    <Preference
+        android:key="qs_tuner"
+        android:title="@string/quick_settings" />
 
-        <SwitchPreference
-            android:key="battery_pct"
-            android:title="@string/show_battery_percentage"
-            android:summary="@string/show_battery_percentage_summary"
-            android:persistent="false" />
+    <PreferenceScreen
+        android:title="@string/status_bar" >
+
+        <com.android.systemui.tuner.StatusBarSwitch
+            android:key="cast"
+            android:title="@string/quick_settings_cast_title" />
+
+        <com.android.systemui.tuner.StatusBarSwitch
+            android:key="hotspot"
+            android:title="@string/quick_settings_hotspot_label" />
+
+        <com.android.systemui.tuner.StatusBarSwitch
+            android:key="bluetooth"
+            android:title="@string/quick_settings_bluetooth_label" />
+
+        <com.android.systemui.tuner.StatusBarSwitch
+            android:key="zen"
+            android:title="@string/quick_settings_dnd_label" />
+
+        <com.android.systemui.tuner.StatusBarSwitch
+            android:key="alarm_clock"
+            android:title="@string/status_bar_alarm" />
+
+        <com.android.systemui.tuner.StatusBarSwitch
+            android:key="managed_profile"
+            android:title="@string/status_bar_work" />
+
+        <com.android.systemui.tuner.StatusBarSwitch
+            android:key="wifi"
+            android:title="@string/quick_settings_wifi_label" />
+
+        <com.android.systemui.tuner.StatusBarSwitch
+            android:key="ethernet"
+            android:title="@string/status_bar_ethernet" />
+
+        <com.android.systemui.tuner.StatusBarSwitch
+            android:key="mobile"
+            android:title="@string/quick_settings_cellular_detail_title" />
+
+        <com.android.systemui.tuner.StatusBarSwitch
+            android:key="airplane"
+            android:title="@string/status_bar_airplane" />
+
+    </PreferenceScreen>
+
+    <SwitchPreference
+        android:key="battery_pct"
+        android:title="@string/show_battery_percentage"
+        android:summary="@string/show_battery_percentage_summary"
+        android:persistent="false" />
 
 </PreferenceScreen>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
index a66f8ec..02e196e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
@@ -18,10 +18,13 @@
 
 import android.content.Context;
 import android.content.res.ColorStateList;
+import android.database.ContentObserver;
 import android.graphics.Color;
 import android.graphics.PorterDuff;
 import android.graphics.drawable.Animatable;
 import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.provider.Settings;
 import android.telephony.SubscriptionInfo;
 import android.util.AttributeSet;
 import android.util.Log;
@@ -33,6 +36,7 @@
 import android.widget.LinearLayout;
 
 import com.android.systemui.R;
+import com.android.systemui.statusbar.phone.StatusBarIconController;
 import com.android.systemui.statusbar.policy.NetworkController.IconState;
 import com.android.systemui.statusbar.policy.NetworkControllerImpl;
 import com.android.systemui.statusbar.policy.SecurityController;
@@ -49,6 +53,11 @@
     static final String TAG = "SignalClusterView";
     static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
+    private static final String SLOT_AIRPLANE = "airplane";
+    private static final String SLOT_MOBILE = "mobile";
+    private static final String SLOT_WIFI = "wifi";
+    private static final String SLOT_ETHERNET = "ethernet";
+
     NetworkControllerImpl mNC;
     SecurityController mSC;
 
@@ -81,6 +90,11 @@
     private int mEndPadding;
     private int mEndPaddingNothingVisible;
 
+    private boolean mBlockAirplane;
+    private boolean mBlockMobile;
+    private boolean mBlockWifi;
+    private boolean mBlockEthernet;
+
     public SignalClusterView(Context context) {
         this(context, null);
     }
@@ -91,6 +105,14 @@
 
     public SignalClusterView(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
+        readBlacklist();
+    }
+
+    private void readBlacklist() {
+        mBlockAirplane = StatusBarIconController.isBlocked(getContext(), SLOT_AIRPLANE);
+        mBlockMobile = StatusBarIconController.isBlocked(getContext(), SLOT_MOBILE);
+        mBlockWifi = StatusBarIconController.isBlocked(getContext(), SLOT_WIFI);
+        mBlockEthernet = StatusBarIconController.isBlocked(getContext(), SLOT_ETHERNET);
     }
 
     public void setNetworkController(NetworkControllerImpl nc) {
@@ -141,6 +163,9 @@
 
         apply();
         applyIconTint();
+        getContext().getContentResolver().registerContentObserver(
+                Settings.Secure.getUriFor(StatusBarIconController.ICON_BLACKLIST), false,
+                mBlacklistObserver);
     }
 
     @Override
@@ -153,6 +178,7 @@
         mAirplane       = null;
         mMobileSignalGroup.removeAllViews();
         mMobileSignalGroup = null;
+        getContext().getContentResolver().unregisterContentObserver(mBlacklistObserver);
 
         super.onDetachedFromWindow();
     }
@@ -172,7 +198,7 @@
     @Override
     public void setWifiIndicators(boolean enabled, IconState statusIcon, IconState qsIcon,
             boolean activityIn, boolean activityOut, String description) {
-        mWifiVisible = statusIcon.visible;
+        mWifiVisible = statusIcon.visible && !mBlockWifi;
         mWifiStrengthId = statusIcon.icon;
         mWifiDescription = statusIcon.contentDescription;
 
@@ -184,7 +210,7 @@
             int qsType, boolean activityIn, boolean activityOut, String typeContentDescription,
             String description, boolean isWide, int subId) {
         PhoneState state = getOrInflateState(subId);
-        state.mMobileVisible = statusIcon.visible;
+        state.mMobileVisible = statusIcon.visible && !mBlockMobile;
         state.mMobileStrengthId = statusIcon.icon;
         state.mMobileTypeId = statusType;
         state.mMobileDescription = statusIcon.contentDescription;
@@ -196,7 +222,7 @@
 
     @Override
     public void setEthernetIndicators(IconState state) {
-        mEthernetVisible = state.visible;
+        mEthernetVisible = state.visible && !mBlockEthernet;
         mEthernetIconId = state.icon;
         mEthernetDescription = state.contentDescription;
 
@@ -205,7 +231,7 @@
 
     @Override
     public void setNoSims(boolean show) {
-        mNoSimsVisible = show;
+        mNoSimsVisible = show && !mBlockMobile;
     }
 
     @Override
@@ -244,7 +270,7 @@
 
     @Override
     public void setIsAirplaneMode(IconState icon) {
-        mIsAirplaneMode = icon.visible;
+        mIsAirplaneMode = icon.visible && !mBlockAirplane;
         mAirplaneIconId = icon.icon;
         mAirplaneContentDescription = icon.contentDescription;
 
@@ -502,5 +528,14 @@
             setTint(mMobileType, tint);
         }
     }
+
+    private final ContentObserver mBlacklistObserver = new ContentObserver(new Handler()) {
+        public void onChange(boolean selfChange) {
+            readBlacklist();
+            // Re-register to get new callbacks.
+            mNC.removeSignalCallback(SignalClusterView.this);
+            mNC.addSignalCallback(SignalClusterView.this);
+        };
+    };
 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index 3294e15..baac8ac 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -18,7 +18,6 @@
 
 import android.app.Notification;
 import android.content.Context;
-import android.content.pm.PackageManager;
 import android.content.res.Resources;
 import android.graphics.Canvas;
 import android.graphics.Paint;
@@ -49,10 +48,17 @@
     private int mNumberY;
     private String mNumberText;
     private Notification mNotification;
+    private final boolean mBlocked;
 
     public StatusBarIconView(Context context, String slot, Notification notification) {
+        this(context, slot, notification, false);
+    }
+
+    public StatusBarIconView(Context context, String slot, Notification notification,
+            boolean blocked) {
         super(context);
         final Resources res = context.getResources();
+        mBlocked = blocked;
         mSlot = slot;
         mNumberPain = new Paint();
         mNumberPain.setTextAlign(Paint.Align.CENTER);
@@ -80,6 +86,7 @@
 
     public StatusBarIconView(Context context, AttributeSet attrs) {
         super(context, attrs);
+        mBlocked = false;
         final Resources res = context.getResources();
         final int outerBounds = res.getDimensionPixelSize(R.dimen.status_bar_icon_size);
         final int imageBounds = res.getDimensionPixelSize(R.dimen.status_bar_icon_drawing_size);
@@ -148,7 +155,7 @@
             invalidate();
         }
         if (!visibilityEquals) {
-            setVisibility(icon.visible ? VISIBLE : GONE);
+            setVisibility(icon.visible && !mBlocked ? VISIBLE : GONE);
         }
         return true;
     }
@@ -281,4 +288,8 @@
         return "StatusBarIconView(slot=" + mSlot + " icon=" + mIcon
             + " notification=" + mNotification + ")";
     }
+
+    public String getSlot() {
+        return mSlot;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
index 45da297..a268077 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
@@ -20,10 +20,14 @@
 import android.animation.ValueAnimator;
 import android.content.Context;
 import android.content.res.ColorStateList;
+import android.database.ContentObserver;
 import android.graphics.Color;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.SystemClock;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.ArraySet;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.animation.AnimationUtils;
@@ -53,6 +57,8 @@
 
     public static final long DEFAULT_TINT_ANIMATION_DURATION = 120;
 
+    public static final String ICON_BLACKLIST = "icon_blacklist";
+
     private Context mContext;
     private PhoneStatusBar mPhoneStatusBar;
     private Interpolator mLinearOutSlowIn;
@@ -89,6 +95,8 @@
     private long mTransitionDeferringStartTime;
     private long mTransitionDeferringDuration;
 
+    private final ArraySet<String> mIconBlacklist;
+
     private final Runnable mTransitionDeferringDoneRunnable = new Runnable() {
         @Override
         public void run() {
@@ -118,7 +126,12 @@
         mDarkModeIconColorSingleTone = context.getColor(R.color.dark_mode_icon_color_single_tone);
         mLightModeIconColorSingleTone = context.getColor(R.color.light_mode_icon_color_single_tone);
         mHandler = new Handler();
+        mIconBlacklist = getIconBlacklist(context);
         updateResources();
+
+        context.getContentResolver().registerContentObserver(
+                Settings.Secure.getUriFor(StatusBarIconController.ICON_BLACKLIST), false,
+                mBlacklistObserver);
     }
 
     public void updateResources() {
@@ -130,11 +143,12 @@
     }
 
     public void addSystemIcon(String slot, int index, int viewIndex, StatusBarIcon icon) {
-        StatusBarIconView view = new StatusBarIconView(mContext, slot, null);
+        boolean blocked = mIconBlacklist.contains(slot);
+        StatusBarIconView view = new StatusBarIconView(mContext, slot, null, blocked);
         view.set(icon);
         mStatusIcons.addView(view, viewIndex, new LinearLayout.LayoutParams(
                 ViewGroup.LayoutParams.WRAP_CONTENT, mIconSize));
-        view = new StatusBarIconView(mContext, slot, null);
+        view = new StatusBarIconView(mContext, slot, null, blocked);
         view.set(icon);
         mStatusIconsKeyguard.addView(view, viewIndex, new LinearLayout.LayoutParams(
                 ViewGroup.LayoutParams.WRAP_CONTENT, mIconSize));
@@ -414,4 +428,43 @@
         }
         mTransitionPending = false;
     }
+
+    private final ContentObserver mBlacklistObserver = new ContentObserver(new Handler()) {
+        public void onChange(boolean selfChange) {
+            mIconBlacklist.clear();
+            mIconBlacklist.addAll(getIconBlacklist(mContext));
+            ArrayList<StatusBarIconView> views = new ArrayList<StatusBarIconView>();
+            // Get all the current views.
+            for (int i = 0; i < mStatusIcons.getChildCount(); i++) {
+                views.add((StatusBarIconView) mStatusIcons.getChildAt(i));
+            }
+            // Remove all the icons.
+            for (int i = views.size() - 1; i >= 0; i--) {
+                removeSystemIcon(views.get(i).getSlot(), i, i);
+            }
+            // Add them all back
+            for (int i = 0; i < views.size(); i++) {
+                addSystemIcon(views.get(i).getSlot(), i, i, views.get(i).getStatusBarIcon());
+            }
+        }
+    };
+
+    public static ArraySet<String> getIconBlacklist(Context context) {
+        String blackListStr = Settings.Secure.getString(context.getContentResolver(),
+                ICON_BLACKLIST);
+        ArraySet<String> ret = new ArraySet<String>();
+        if (blackListStr != null) {
+            String[] blacklist = blackListStr.split(",");
+            for (String slot : blacklist) {
+                if (!TextUtils.isEmpty(slot)) {
+                    ret.add(slot);
+                }
+            }
+        }
+        return ret;
+    }
+
+    public static boolean isBlocked(Context context, String slot) {
+        return getIconBlacklist(context).contains(slot);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/QsTuner.java b/packages/SystemUI/src/com/android/systemui/tuner/QsTuner.java
index 90c1897..9f593fc 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/QsTuner.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/QsTuner.java
@@ -22,6 +22,7 @@
 import android.content.DialogInterface;
 import android.os.Bundle;
 import android.provider.Settings.Secure;
+import android.text.TextUtils;
 import android.util.Log;
 import android.view.DragEvent;
 import android.view.LayoutInflater;
@@ -32,7 +33,6 @@
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.view.View.OnDragListener;
-import android.view.View.OnLongClickListener;
 import android.view.View.OnTouchListener;
 import android.view.ViewGroup;
 import android.widget.EditText;
@@ -47,6 +47,7 @@
 import com.android.systemui.qs.QSTileView;
 import com.android.systemui.qs.tiles.IntentTile;
 import com.android.systemui.statusbar.phone.QSTileHost;
+import com.android.systemui.statusbar.policy.SecurityController;
 
 import java.util.List;
 
@@ -174,7 +175,7 @@
 
         public CustomHost(Context context) {
             super(context, null, null, null, null, null, null, null, null, null,
-                    null, null, null);
+                    null, null, new BlankSecurityController());
         }
 
         @Override
@@ -215,15 +216,8 @@
         }
 
         private void setTiles(List<String> tiles) {
-            StringBuilder builder = new StringBuilder();
-            for (int i = 0; i < tiles.size(); i++) {
-                if (builder.length() != 0) {
-                    builder.append(',');
-                }
-                builder.append(tiles.get(i));
-            }
-            Secure.putStringForUser(getContext().getContentResolver(),
-                    TILES_SETTING, builder.toString(), mUserTracker.getCurrentUserId());
+            Secure.putStringForUser(getContext().getContentResolver(), TILES_SETTING,
+                    TextUtils.join(",", tiles), mUserTracker.getCurrentUserId());
         }
 
         public void showAddDialog() {
@@ -282,6 +276,45 @@
             }
             return true;
         }
+
+        private static class BlankSecurityController implements SecurityController {
+            @Override
+            public boolean hasDeviceOwner() {
+                return false;
+            }
+
+            @Override
+            public boolean hasProfileOwner() {
+                return false;
+            }
+
+            @Override
+            public String getDeviceOwnerName() {
+                return null;
+            }
+
+            @Override
+            public String getProfileOwnerName() {
+                return null;
+            }
+
+            @Override
+            public boolean isVpnEnabled() {
+                return false;
+            }
+
+            @Override
+            public void onUserSwitched(int newUserId) {
+            }
+
+            @Override
+            public void addCallback(SecurityControllerCallback callback) {
+            }
+
+            @Override
+            public void removeCallback(SecurityControllerCallback callback) {
+            }
+        }
     }
 
     private static class DraggableTile extends QSTile<QSTile.State>
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/StatusBarSwitch.java b/packages/SystemUI/src/com/android/systemui/tuner/StatusBarSwitch.java
new file mode 100644
index 0000000..8158a68
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tuner/StatusBarSwitch.java
@@ -0,0 +1,58 @@
+/*
+ * 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.tuner;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.preference.SwitchPreference;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+
+import com.android.systemui.statusbar.phone.StatusBarIconController;
+
+import java.util.Set;
+
+public class StatusBarSwitch extends SwitchPreference {
+
+    public StatusBarSwitch(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        setChecked(!StatusBarIconController.isBlocked(getContext(), getKey()));
+    }
+
+    @Override
+    protected boolean persistBoolean(boolean value) {
+        Set<String> blacklist = StatusBarIconController.getIconBlacklist(getContext());
+        if (!value) {
+            // If not enabled add to blacklist.
+            if (!blacklist.contains(getKey())) {
+                blacklist.add(getKey());
+                setList(blacklist);
+            }
+        } else {
+            if (blacklist != null && blacklist.remove(getKey())) {
+                setList(blacklist);
+            }
+        }
+        return true;
+    }
+
+    private void setList(Set<String> blacklist) {
+        ContentResolver contentResolver = getContext().getContentResolver();
+        Settings.Secure.putString(contentResolver, StatusBarIconController.ICON_BLACKLIST,
+                TextUtils.join(",", blacklist));
+    }
+}