| /* |
| * Copyright (C) 2017 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.statusbar.phone; |
| |
| import static android.app.StatusBarManager.DISABLE2_SYSTEM_ICONS; |
| import static android.app.StatusBarManager.DISABLE_NONE; |
| import static com.android.systemui.statusbar.phone.StatusBarIconHolder.TYPE_ICON; |
| import static com.android.systemui.statusbar.phone.StatusBarIconHolder.TYPE_MOBILE; |
| import static com.android.systemui.statusbar.phone.StatusBarIconHolder.TYPE_WIFI; |
| |
| import android.content.Context; |
| import android.os.Bundle; |
| import android.support.annotation.VisibleForTesting; |
| import android.text.TextUtils; |
| import android.util.ArraySet; |
| import android.util.Log; |
| import android.view.Gravity; |
| import android.view.View; |
| import android.view.ViewGroup; |
| import android.widget.ImageView; |
| import android.widget.LinearLayout; |
| import android.widget.LinearLayout.LayoutParams; |
| |
| import com.android.internal.statusbar.StatusBarIcon; |
| import com.android.systemui.DemoMode; |
| import com.android.systemui.Dependency; |
| import com.android.systemui.R; |
| import com.android.systemui.statusbar.StatusIconDisplayable; |
| import com.android.systemui.statusbar.StatusBarIconView; |
| import com.android.systemui.statusbar.StatusBarMobileView; |
| import com.android.systemui.statusbar.StatusBarWifiView; |
| import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.MobileIconState; |
| import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.WifiIconState; |
| import com.android.systemui.statusbar.policy.DarkIconDispatcher; |
| import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver; |
| import com.android.systemui.util.Utils.DisableStateTracker; |
| import java.util.List; |
| |
| public interface StatusBarIconController { |
| |
| /** |
| * When an icon is added with TAG_PRIMARY, it will be treated as the primary icon |
| * in that slot and not added as a sub slot. |
| */ |
| public static final int TAG_PRIMARY = 0; |
| |
| public void addIconGroup(IconManager iconManager); |
| public void removeIconGroup(IconManager iconManager); |
| public void setExternalIcon(String slot); |
| public void setIcon(String slot, int resourceId, CharSequence contentDescription); |
| public void setIcon(String slot, StatusBarIcon icon); |
| public void setSignalIcon(String slot, WifiIconState state); |
| public void setMobileIcons(String slot, List<MobileIconState> states); |
| public void setIconVisibility(String slot, boolean b); |
| /** |
| * If you don't know what to pass for `tag`, either remove all icons for slot, or use |
| * TAG_PRIMARY to refer to the first icon at a given slot. |
| */ |
| public void removeIcon(String slot, int tag); |
| public void removeAllIconsForSlot(String slot); |
| |
| public static final String ICON_BLACKLIST = "icon_blacklist"; |
| |
| public static ArraySet<String> getIconBlacklist(String blackListStr) { |
| ArraySet<String> ret = new ArraySet<>(); |
| if (blackListStr == null) { |
| blackListStr = "rotate,headset"; |
| } |
| String[] blacklist = blackListStr.split(","); |
| for (String slot : blacklist) { |
| if (!TextUtils.isEmpty(slot)) { |
| ret.add(slot); |
| } |
| } |
| return ret; |
| } |
| |
| /** |
| * Version of ViewGroup that observes state from the DarkIconDispatcher. |
| */ |
| public static class DarkIconManager extends IconManager { |
| private final DarkIconDispatcher mDarkIconDispatcher; |
| private int mIconHPadding; |
| |
| public DarkIconManager(LinearLayout linearLayout) { |
| super(linearLayout); |
| mIconHPadding = mContext.getResources().getDimensionPixelSize( |
| R.dimen.status_bar_icon_padding); |
| mDarkIconDispatcher = Dependency.get(DarkIconDispatcher.class); |
| } |
| |
| @Override |
| protected void onIconAdded(int index, String slot, boolean blocked, |
| StatusBarIconHolder holder) { |
| StatusIconDisplayable view = addHolder(index, slot, blocked, holder); |
| mDarkIconDispatcher.addDarkReceiver((DarkReceiver) view); |
| } |
| |
| @Override |
| protected LayoutParams onCreateLayoutParams() { |
| LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams( |
| ViewGroup.LayoutParams.WRAP_CONTENT, mIconSize); |
| lp.setMargins(mIconHPadding, 0, mIconHPadding, 0); |
| return lp; |
| } |
| |
| @Override |
| protected void destroy() { |
| for (int i = 0; i < mGroup.getChildCount(); i++) { |
| mDarkIconDispatcher.removeDarkReceiver((DarkReceiver) mGroup.getChildAt(i)); |
| } |
| mGroup.removeAllViews(); |
| } |
| |
| @Override |
| protected void onRemoveIcon(int viewIndex) { |
| mDarkIconDispatcher.removeDarkReceiver((DarkReceiver) mGroup.getChildAt(viewIndex)); |
| super.onRemoveIcon(viewIndex); |
| } |
| |
| @Override |
| public void onSetIcon(int viewIndex, StatusBarIcon icon) { |
| super.onSetIcon(viewIndex, icon); |
| mDarkIconDispatcher.applyDark((DarkReceiver) mGroup.getChildAt(viewIndex)); |
| } |
| |
| @Override |
| protected DemoStatusIcons createDemoStatusIcons() { |
| DemoStatusIcons icons = super.createDemoStatusIcons(); |
| mDarkIconDispatcher.addDarkReceiver(icons); |
| |
| return icons; |
| } |
| |
| @Override |
| protected void exitDemoMode() { |
| mDarkIconDispatcher.removeDarkReceiver(mDemoStatusIcons); |
| super.exitDemoMode(); |
| } |
| } |
| |
| public static class TintedIconManager extends IconManager { |
| private int mColor; |
| |
| public TintedIconManager(ViewGroup group) { |
| super(group); |
| } |
| |
| @Override |
| protected void onIconAdded(int index, String slot, boolean blocked, |
| StatusBarIconHolder holder) { |
| StatusIconDisplayable view = addHolder(index, slot, blocked, holder); |
| view.setStaticDrawableColor(mColor); |
| } |
| |
| public void setTint(int color) { |
| mColor = color; |
| for (int i = 0; i < mGroup.getChildCount(); i++) { |
| View child = mGroup.getChildAt(i); |
| if (child instanceof StatusIconDisplayable) { |
| StatusIconDisplayable icon = (StatusIconDisplayable) child; |
| icon.setStaticDrawableColor(mColor); |
| } |
| } |
| } |
| |
| @Override |
| protected DemoStatusIcons createDemoStatusIcons() { |
| DemoStatusIcons icons = super.createDemoStatusIcons(); |
| icons.setColor(mColor); |
| return icons; |
| } |
| } |
| |
| /** |
| * Turns info from StatusBarIconController into ImageViews in a ViewGroup. |
| */ |
| public static class IconManager implements DemoMode { |
| protected final ViewGroup mGroup; |
| protected final Context mContext; |
| protected final int mIconSize; |
| // Whether or not these icons show up in dumpsys |
| protected boolean mShouldLog = false; |
| |
| // Enables SystemUI demo mode to take effect in this group |
| protected boolean mDemoable = true; |
| private boolean mIsInDemoMode; |
| protected DemoStatusIcons mDemoStatusIcons; |
| |
| public IconManager(ViewGroup group) { |
| mGroup = group; |
| mContext = group.getContext(); |
| mIconSize = mContext.getResources().getDimensionPixelSize( |
| com.android.internal.R.dimen.status_bar_icon_size); |
| |
| DisableStateTracker tracker = |
| new DisableStateTracker(DISABLE_NONE, DISABLE2_SYSTEM_ICONS); |
| mGroup.addOnAttachStateChangeListener(tracker); |
| if (mGroup.isAttachedToWindow()) { |
| // In case we miss the first onAttachedToWindow event |
| tracker.onViewAttachedToWindow(mGroup); |
| } |
| } |
| |
| public boolean isDemoable() { |
| return mDemoable; |
| } |
| |
| public void setIsDemoable(boolean demoable) { |
| mDemoable = demoable; |
| } |
| |
| public void setShouldLog(boolean should) { |
| mShouldLog = should; |
| } |
| |
| public boolean shouldLog() { |
| return mShouldLog; |
| } |
| |
| protected void onIconAdded(int index, String slot, boolean blocked, |
| StatusBarIconHolder holder) { |
| addHolder(index, slot, blocked, holder); |
| } |
| |
| protected StatusIconDisplayable addHolder(int index, String slot, boolean blocked, |
| StatusBarIconHolder holder) { |
| switch (holder.getType()) { |
| case TYPE_ICON: |
| return addIcon(index, slot, blocked, holder.getIcon()); |
| |
| case TYPE_WIFI: |
| return addSignalIcon(index, slot, holder.getWifiState()); |
| |
| case TYPE_MOBILE: |
| return addMobileIcon(index, slot, holder.getMobileState()); |
| } |
| |
| return null; |
| } |
| |
| @VisibleForTesting |
| protected StatusBarIconView addIcon(int index, String slot, boolean blocked, |
| StatusBarIcon icon) { |
| StatusBarIconView view = onCreateStatusBarIconView(slot, blocked); |
| view.set(icon); |
| mGroup.addView(view, index, onCreateLayoutParams()); |
| return view; |
| } |
| |
| @VisibleForTesting |
| protected StatusBarWifiView addSignalIcon(int index, String slot, WifiIconState state) { |
| StatusBarWifiView view = onCreateStatusBarWifiView(slot); |
| view.applyWifiState(state); |
| mGroup.addView(view, index, onCreateLayoutParams()); |
| |
| if (mIsInDemoMode) { |
| mDemoStatusIcons.addDemoWifiView(state); |
| } |
| return view; |
| } |
| |
| @VisibleForTesting |
| protected StatusBarMobileView addMobileIcon(int index, String slot, MobileIconState state) { |
| StatusBarMobileView view = onCreateStatusBarMobileView(slot); |
| view.applyMobileState(state); |
| mGroup.addView(view, index, onCreateLayoutParams()); |
| |
| if (mIsInDemoMode) { |
| mDemoStatusIcons.addMobileView(state); |
| } |
| return view; |
| } |
| |
| private StatusBarIconView onCreateStatusBarIconView(String slot, boolean blocked) { |
| return new StatusBarIconView(mContext, slot, null, blocked); |
| } |
| |
| private StatusBarWifiView onCreateStatusBarWifiView(String slot) { |
| StatusBarWifiView view = StatusBarWifiView.fromContext(mContext); |
| view.setSlot(slot); |
| return view; |
| } |
| |
| private StatusBarMobileView onCreateStatusBarMobileView(String slot) { |
| StatusBarMobileView view = StatusBarMobileView.fromContext(mContext); |
| view.setSlot(slot); |
| return view; |
| } |
| |
| protected LinearLayout.LayoutParams onCreateLayoutParams() { |
| return new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, mIconSize); |
| } |
| |
| protected void destroy() { |
| mGroup.removeAllViews(); |
| } |
| |
| protected void onIconExternal(int viewIndex, int height) { |
| ImageView imageView = (ImageView) mGroup.getChildAt(viewIndex); |
| imageView.setScaleType(ImageView.ScaleType.FIT_CENTER); |
| imageView.setAdjustViewBounds(true); |
| setHeightAndCenter(imageView, height); |
| } |
| |
| protected void onDensityOrFontScaleChanged() { |
| for (int i = 0; i < mGroup.getChildCount(); i++) { |
| View child = mGroup.getChildAt(i); |
| LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams( |
| ViewGroup.LayoutParams.WRAP_CONTENT, mIconSize); |
| child.setLayoutParams(lp); |
| } |
| } |
| |
| private void setHeightAndCenter(ImageView imageView, int height) { |
| ViewGroup.LayoutParams params = imageView.getLayoutParams(); |
| params.height = height; |
| if (params instanceof LinearLayout.LayoutParams) { |
| ((LinearLayout.LayoutParams) params).gravity = Gravity.CENTER_VERTICAL; |
| } |
| imageView.setLayoutParams(params); |
| } |
| |
| protected void onRemoveIcon(int viewIndex) { |
| if (mIsInDemoMode) { |
| mDemoStatusIcons.onRemoveIcon((StatusIconDisplayable) mGroup.getChildAt(viewIndex)); |
| } |
| mGroup.removeViewAt(viewIndex); |
| } |
| |
| public void onSetIcon(int viewIndex, StatusBarIcon icon) { |
| StatusBarIconView view = (StatusBarIconView) mGroup.getChildAt(viewIndex); |
| view.set(icon); |
| } |
| |
| public void onSetIconHolder(int viewIndex, StatusBarIconHolder holder) { |
| switch (holder.getType()) { |
| case TYPE_ICON: |
| onSetIcon(viewIndex, holder.getIcon()); |
| return; |
| case TYPE_WIFI: |
| onSetSignalIcon(viewIndex, holder.getWifiState()); |
| return; |
| |
| case TYPE_MOBILE: |
| onSetMobileIcon(viewIndex, holder.getMobileState()); |
| default: |
| break; |
| } |
| } |
| |
| public void onSetSignalIcon(int viewIndex, WifiIconState state) { |
| StatusBarWifiView wifiView = (StatusBarWifiView) mGroup.getChildAt(viewIndex); |
| if (wifiView != null) { |
| wifiView.applyWifiState(state); |
| } |
| |
| if (mIsInDemoMode) { |
| mDemoStatusIcons.updateWifiState(state); |
| } |
| } |
| |
| public void onSetMobileIcon(int viewIndex, MobileIconState state) { |
| StatusBarMobileView view = (StatusBarMobileView) mGroup.getChildAt(viewIndex); |
| if (view != null) { |
| view.applyMobileState(state); |
| } |
| |
| if (mIsInDemoMode) { |
| mDemoStatusIcons.updateMobileState(state); |
| } |
| } |
| |
| @Override |
| public void dispatchDemoCommand(String command, Bundle args) { |
| if (!mDemoable) { |
| return; |
| } |
| |
| if (command.equals(COMMAND_EXIT)) { |
| if (mDemoStatusIcons != null) { |
| mDemoStatusIcons.dispatchDemoCommand(command, args); |
| exitDemoMode(); |
| } |
| mIsInDemoMode = false; |
| } else { |
| if (mDemoStatusIcons == null) { |
| mIsInDemoMode = true; |
| mDemoStatusIcons = createDemoStatusIcons(); |
| } |
| mDemoStatusIcons.dispatchDemoCommand(command, args); |
| } |
| } |
| |
| protected void exitDemoMode() { |
| mDemoStatusIcons.remove(); |
| mDemoStatusIcons = null; |
| } |
| |
| protected DemoStatusIcons createDemoStatusIcons() { |
| return new DemoStatusIcons((LinearLayout) mGroup, mIconSize); |
| } |
| } |
| } |