Home | History | Annotate | Download | only in statusbar
      1 /*
      2  * Copyright (C) 2015 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License
     15  */
     16 
     17 package com.android.systemui.statusbar;
     18 
     19 import com.android.internal.util.Preconditions;
     20 import com.android.systemui.statusbar.phone.StatusBarWindowManager;
     21 import com.android.systemui.statusbar.policy.HeadsUpManager;
     22 import com.android.systemui.statusbar.policy.RemoteInputView;
     23 
     24 import android.util.ArraySet;
     25 
     26 import java.lang.ref.WeakReference;
     27 import java.util.ArrayList;
     28 
     29 /**
     30  * Keeps track of the currently active {@link RemoteInputView}s.
     31  */
     32 public class RemoteInputController {
     33 
     34     private final ArrayList<WeakReference<NotificationData.Entry>> mOpen = new ArrayList<>();
     35     private final ArraySet<String> mSpinning = new ArraySet<>();
     36     private final ArrayList<Callback> mCallbacks = new ArrayList<>(3);
     37     private final HeadsUpManager mHeadsUpManager;
     38 
     39     public RemoteInputController(StatusBarWindowManager sbwm, HeadsUpManager headsUpManager) {
     40         addCallback(sbwm);
     41         mHeadsUpManager = headsUpManager;
     42     }
     43 
     44     public void addRemoteInput(NotificationData.Entry entry) {
     45         Preconditions.checkNotNull(entry);
     46 
     47         boolean found = pruneWeakThenRemoveAndContains(
     48                 entry /* contains */, null /* remove */);
     49         if (!found) {
     50             mOpen.add(new WeakReference<>(entry));
     51         }
     52 
     53         apply(entry);
     54     }
     55 
     56     public void removeRemoteInput(NotificationData.Entry entry) {
     57         Preconditions.checkNotNull(entry);
     58 
     59         pruneWeakThenRemoveAndContains(null /* contains */, entry /* remove */);
     60 
     61         apply(entry);
     62     }
     63 
     64     public void addSpinning(String key) {
     65         mSpinning.add(key);
     66     }
     67 
     68     public void removeSpinning(String key) {
     69         mSpinning.remove(key);
     70     }
     71 
     72     public boolean isSpinning(String key) {
     73         return mSpinning.contains(key);
     74     }
     75 
     76     private void apply(NotificationData.Entry entry) {
     77         mHeadsUpManager.setRemoteInputActive(entry, isRemoteInputActive(entry));
     78         boolean remoteInputActive = isRemoteInputActive();
     79         int N = mCallbacks.size();
     80         for (int i = 0; i < N; i++) {
     81             mCallbacks.get(i).onRemoteInputActive(remoteInputActive);
     82         }
     83     }
     84 
     85     /**
     86      * @return true if {@param entry} has an active RemoteInput
     87      */
     88     public boolean isRemoteInputActive(NotificationData.Entry entry) {
     89         return pruneWeakThenRemoveAndContains(entry /* contains */, null /* remove */);
     90     }
     91 
     92     /**
     93      * @return true if any entry has an active RemoteInput
     94      */
     95     public boolean isRemoteInputActive() {
     96         pruneWeakThenRemoveAndContains(null /* contains */, null /* remove */);
     97         return !mOpen.isEmpty();
     98     }
     99 
    100     /**
    101      * Prunes dangling weak references, removes entries referring to {@param remove} and returns
    102      * whether {@param contains} is part of the array in a single loop.
    103      * @param remove if non-null, removes this entry from the active remote inputs
    104      * @return true if {@param contains} is in the set of active remote inputs
    105      */
    106     private boolean pruneWeakThenRemoveAndContains(
    107             NotificationData.Entry contains, NotificationData.Entry remove) {
    108         boolean found = false;
    109         for (int i = mOpen.size() - 1; i >= 0; i--) {
    110             NotificationData.Entry item = mOpen.get(i).get();
    111             if (item == null || item == remove) {
    112                 mOpen.remove(i);
    113             } else if (item == contains) {
    114                 found = true;
    115             }
    116         }
    117         return found;
    118     }
    119 
    120 
    121     public void addCallback(Callback callback) {
    122         Preconditions.checkNotNull(callback);
    123         mCallbacks.add(callback);
    124     }
    125 
    126     public void remoteInputSent(NotificationData.Entry entry) {
    127         int N = mCallbacks.size();
    128         for (int i = 0; i < N; i++) {
    129             mCallbacks.get(i).onRemoteInputSent(entry);
    130         }
    131     }
    132 
    133     public void closeRemoteInputs() {
    134         if (mOpen.size() == 0) {
    135             return;
    136         }
    137 
    138         // Make a copy because closing the remote inputs will modify mOpen.
    139         ArrayList<NotificationData.Entry> list = new ArrayList<>(mOpen.size());
    140         for (int i = mOpen.size() - 1; i >= 0; i--) {
    141             NotificationData.Entry item = mOpen.get(i).get();
    142             if (item != null && item.row != null) {
    143                 list.add(item);
    144             }
    145         }
    146 
    147         for (int i = list.size() - 1; i >= 0; i--) {
    148             NotificationData.Entry item = list.get(i);
    149             if (item.row != null) {
    150                 item.row.closeRemoteInput();
    151             }
    152         }
    153     }
    154 
    155     public interface Callback {
    156         default void onRemoteInputActive(boolean active) {}
    157 
    158         default void onRemoteInputSent(NotificationData.Entry entry) {}
    159     }
    160 }
    161