/* * 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.statusbar.phone; import android.animation.ArgbEvaluator; import android.animation.ValueAnimator; import android.content.Context; import android.content.res.ColorStateList; import android.graphics.Color; import android.os.Bundle; import android.os.Handler; import android.os.SystemClock; import android.text.TextUtils; import android.util.ArraySet; import android.view.View; import android.view.ViewGroup; import android.view.animation.AnimationUtils; import android.view.animation.Interpolator; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; import com.android.internal.statusbar.StatusBarIcon; import com.android.internal.util.NotificationColorUtil; import com.android.systemui.BatteryMeterView; import com.android.systemui.FontSizeUtils; import com.android.systemui.R; import com.android.systemui.statusbar.NotificationData; import com.android.systemui.statusbar.SignalClusterView; import com.android.systemui.statusbar.StatusBarIconView; import com.android.systemui.tuner.TunerService; import com.android.systemui.tuner.TunerService.Tunable; import java.io.PrintWriter; import java.util.ArrayList; /** * Controls everything regarding the icons in the status bar and on Keyguard, including, but not * limited to: notification icons, signal cluster, additional status icons, and clock in the status * bar. */ public class StatusBarIconController implements Tunable { 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; private Interpolator mFastOutSlowIn; private DemoStatusIcons mDemoStatusIcons; private NotificationColorUtil mNotificationColorUtil; private LinearLayout mSystemIconArea; private LinearLayout mStatusIcons; private SignalClusterView mSignalCluster; private LinearLayout mStatusIconsKeyguard; private IconMerger mNotificationIcons; private View mNotificationIconArea; private ImageView mMoreIcon; private BatteryMeterView mBatteryMeterView; private TextView mClock; private int mIconSize; private int mIconHPadding; private int mIconTint = Color.WHITE; private float mDarkIntensity; private boolean mTransitionPending; private boolean mTintChangePending; private float mPendingDarkIntensity; private ValueAnimator mTintAnimator; private int mDarkModeIconColorSingleTone; private int mLightModeIconColorSingleTone; private final Handler mHandler; private boolean mTransitionDeferring; private long mTransitionDeferringStartTime; private long mTransitionDeferringDuration; private final ArraySet mIconBlacklist = new ArraySet<>(); private final Runnable mTransitionDeferringDoneRunnable = new Runnable() { @Override public void run() { mTransitionDeferring = false; } }; public StatusBarIconController(Context context, View statusBar, View keyguardStatusBar, PhoneStatusBar phoneStatusBar) { mContext = context; mPhoneStatusBar = phoneStatusBar; mNotificationColorUtil = NotificationColorUtil.getInstance(context); mSystemIconArea = (LinearLayout) statusBar.findViewById(R.id.system_icon_area); mStatusIcons = (LinearLayout) statusBar.findViewById(R.id.statusIcons); mSignalCluster = (SignalClusterView) statusBar.findViewById(R.id.signal_cluster); mNotificationIconArea = statusBar.findViewById(R.id.notification_icon_area_inner); mNotificationIcons = (IconMerger) statusBar.findViewById(R.id.notificationIcons); mMoreIcon = (ImageView) statusBar.findViewById(R.id.moreIcon); mNotificationIcons.setOverflowIndicator(mMoreIcon); mStatusIconsKeyguard = (LinearLayout) keyguardStatusBar.findViewById(R.id.statusIcons); mBatteryMeterView = (BatteryMeterView) statusBar.findViewById(R.id.battery); mClock = (TextView) statusBar.findViewById(R.id.clock); mLinearOutSlowIn = AnimationUtils.loadInterpolator(mContext, android.R.interpolator.linear_out_slow_in); mFastOutSlowIn = AnimationUtils.loadInterpolator(mContext, android.R.interpolator.fast_out_slow_in); 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(); updateResources(); TunerService.get(mContext).addTunable(this, ICON_BLACKLIST); } @Override public void onTuningChanged(String key, String newValue) { if (!ICON_BLACKLIST.equals(key)) { return; } mIconBlacklist.clear(); mIconBlacklist.addAll(getIconBlacklist(newValue)); ArrayList views = new ArrayList(); // 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 void updateResources() { mIconSize = mContext.getResources().getDimensionPixelSize( com.android.internal.R.dimen.status_bar_icon_size); mIconHPadding = mContext.getResources().getDimensionPixelSize( R.dimen.status_bar_icon_padding); FontSizeUtils.updateFontSize(mClock, R.dimen.status_bar_clock_size); } public void addSystemIcon(String slot, int index, int viewIndex, StatusBarIcon icon) { 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, blocked); view.set(icon); mStatusIconsKeyguard.addView(view, viewIndex, new LinearLayout.LayoutParams( ViewGroup.LayoutParams.WRAP_CONTENT, mIconSize)); applyIconTint(); } public void updateSystemIcon(String slot, int index, int viewIndex, StatusBarIcon old, StatusBarIcon icon) { StatusBarIconView view = (StatusBarIconView) mStatusIcons.getChildAt(viewIndex); view.set(icon); view = (StatusBarIconView) mStatusIconsKeyguard.getChildAt(viewIndex); view.set(icon); applyIconTint(); } public void removeSystemIcon(String slot, int index, int viewIndex) { mStatusIcons.removeViewAt(viewIndex); mStatusIconsKeyguard.removeViewAt(viewIndex); } public void updateNotificationIcons(NotificationData notificationData) { final LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( mIconSize + 2*mIconHPadding, mPhoneStatusBar.getStatusBarHeight()); ArrayList activeNotifications = notificationData.getActiveNotifications(); final int N = activeNotifications.size(); ArrayList toShow = new ArrayList<>(N); // Filter out ambient notifications and notification children. for (int i = 0; i < N; i++) { NotificationData.Entry ent = activeNotifications.get(i); if (notificationData.isAmbient(ent.key) && !NotificationData.showNotificationEvenIfUnprovisioned(ent.notification)) { continue; } if (!PhoneStatusBar.isTopLevelChild(ent)) { continue; } toShow.add(ent.icon); } ArrayList toRemove = new ArrayList<>(); for (int i=0; i