1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file 5 * except in compliance with the License. You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software distributed under the 10 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 11 * KIND, either express or implied. See the License for the specific language governing 12 * permissions and limitations under the License. 13 */ 14 15 package com.android.systemui.statusbar.phone; 16 17 import static com.android.systemui.plugins.DarkIconDispatcher.getTint; 18 19 import android.animation.ArgbEvaluator; 20 import android.content.Context; 21 import android.content.res.ColorStateList; 22 import android.graphics.Rect; 23 import android.util.ArrayMap; 24 import android.widget.ImageView; 25 26 import com.android.systemui.R; 27 import com.android.systemui.dagger.SysUISingleton; 28 import com.android.systemui.dump.DumpManager; 29 30 import java.io.PrintWriter; 31 import java.util.ArrayList; 32 33 import javax.inject.Inject; 34 35 import kotlinx.coroutines.flow.FlowKt; 36 import kotlinx.coroutines.flow.MutableStateFlow; 37 import kotlinx.coroutines.flow.StateFlow; 38 import kotlinx.coroutines.flow.StateFlowKt; 39 40 /** 41 */ 42 @SysUISingleton 43 public class DarkIconDispatcherImpl implements SysuiDarkIconDispatcher, 44 LightBarTransitionsController.DarkIntensityApplier { 45 46 private final LightBarTransitionsController mTransitionsController; 47 private final ArrayList<Rect> mTintAreas = new ArrayList<>(); 48 private final ArrayMap<Object, DarkReceiver> mReceivers = new ArrayMap<>(); 49 50 private int mIconTint = DEFAULT_ICON_TINT; 51 private float mDarkIntensity; 52 private int mDarkModeIconColorSingleTone; 53 private int mLightModeIconColorSingleTone; 54 55 private final MutableStateFlow<DarkChange> mDarkChangeFlow = StateFlowKt.MutableStateFlow( 56 DarkChange.EMPTY); 57 58 /** 59 */ 60 @Inject DarkIconDispatcherImpl( Context context, LightBarTransitionsController.Factory lightBarTransitionsControllerFactory, DumpManager dumpManager)61 public DarkIconDispatcherImpl( 62 Context context, 63 LightBarTransitionsController.Factory lightBarTransitionsControllerFactory, 64 DumpManager dumpManager) { 65 mDarkModeIconColorSingleTone = context.getColor(R.color.dark_mode_icon_color_single_tone); 66 mLightModeIconColorSingleTone = context.getColor(R.color.light_mode_icon_color_single_tone); 67 68 mTransitionsController = lightBarTransitionsControllerFactory.create(this); 69 70 dumpManager.registerDumpable(getClass().getSimpleName(), this); 71 } 72 getTransitionsController()73 public LightBarTransitionsController getTransitionsController() { 74 return mTransitionsController; 75 } 76 77 @Override darkChangeFlow()78 public StateFlow<DarkChange> darkChangeFlow() { 79 return FlowKt.asStateFlow(mDarkChangeFlow); 80 } 81 addDarkReceiver(DarkReceiver receiver)82 public void addDarkReceiver(DarkReceiver receiver) { 83 mReceivers.put(receiver, receiver); 84 receiver.onDarkChanged(mTintAreas, mDarkIntensity, mIconTint); 85 } 86 addDarkReceiver(ImageView imageView)87 public void addDarkReceiver(ImageView imageView) { 88 DarkReceiver receiver = (area, darkIntensity, tint) -> imageView.setImageTintList( 89 ColorStateList.valueOf(getTint(mTintAreas, imageView, mIconTint))); 90 mReceivers.put(imageView, receiver); 91 receiver.onDarkChanged(mTintAreas, mDarkIntensity, mIconTint); 92 } 93 removeDarkReceiver(DarkReceiver object)94 public void removeDarkReceiver(DarkReceiver object) { 95 mReceivers.remove(object); 96 } 97 removeDarkReceiver(ImageView object)98 public void removeDarkReceiver(ImageView object) { 99 mReceivers.remove(object); 100 } 101 applyDark(DarkReceiver object)102 public void applyDark(DarkReceiver object) { 103 mReceivers.get(object).onDarkChanged(mTintAreas, mDarkIntensity, mIconTint); 104 } 105 106 /** 107 * Sets the dark area so {@link #applyDark} only affects the icons in the specified area. 108 * 109 * @param darkAreas the areas in which icons should change it's tint, in logical screen 110 * coordinates 111 */ setIconsDarkArea(ArrayList<Rect> darkAreas)112 public void setIconsDarkArea(ArrayList<Rect> darkAreas) { 113 if (darkAreas == null && mTintAreas.isEmpty()) { 114 return; 115 } 116 117 mTintAreas.clear(); 118 if (darkAreas != null) { 119 mTintAreas.addAll(darkAreas); 120 } 121 applyIconTint(); 122 } 123 124 @Override applyDarkIntensity(float darkIntensity)125 public void applyDarkIntensity(float darkIntensity) { 126 mDarkIntensity = darkIntensity; 127 mIconTint = (int) ArgbEvaluator.getInstance().evaluate(darkIntensity, 128 mLightModeIconColorSingleTone, mDarkModeIconColorSingleTone); 129 applyIconTint(); 130 } 131 132 @Override getTintAnimationDuration()133 public int getTintAnimationDuration() { 134 return LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION; 135 } 136 applyIconTint()137 private void applyIconTint() { 138 mDarkChangeFlow.setValue(new DarkChange(mTintAreas, mDarkIntensity, mIconTint)); 139 for (int i = 0; i < mReceivers.size(); i++) { 140 mReceivers.valueAt(i).onDarkChanged(mTintAreas, mDarkIntensity, mIconTint); 141 } 142 } 143 144 @Override dump(PrintWriter pw, String[] args)145 public void dump(PrintWriter pw, String[] args) { 146 pw.println("DarkIconDispatcher: "); 147 pw.println(" mIconTint: 0x" + Integer.toHexString(mIconTint)); 148 pw.println(" mDarkIntensity: " + mDarkIntensity + "f"); 149 pw.println(" mTintAreas: " + mTintAreas); 150 } 151 } 152