Home | History | Annotate | Download | only in stackdivider
      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.stackdivider;
     18 
     19 import android.content.res.Configuration;
     20 import android.os.RemoteException;
     21 import android.view.IDockedStackListener;
     22 import android.view.LayoutInflater;
     23 import android.view.View;
     24 
     25 import com.android.systemui.R;
     26 import com.android.systemui.SystemUI;
     27 import com.android.systemui.recents.Recents;
     28 import com.android.systemui.recents.events.EventBus;
     29 import com.android.systemui.recents.events.ui.RecentsDrawnEvent;
     30 import com.android.systemui.recents.misc.SystemServicesProxy;
     31 
     32 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
     33 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
     34 
     35 import java.io.FileDescriptor;
     36 import java.io.PrintWriter;
     37 
     38 /**
     39  * Controls the docked stack divider.
     40  */
     41 public class Divider extends SystemUI {
     42     private DividerWindowManager mWindowManager;
     43     private DividerView mView;
     44     private final DividerState mDividerState = new DividerState();
     45     private DockDividerVisibilityListener mDockDividerVisibilityListener;
     46     private boolean mVisible = false;
     47     private boolean mMinimized = false;
     48     private boolean mAdjustedForIme = false;
     49     private boolean mHomeStackResizable = false;
     50     private ForcedResizableInfoActivityController mForcedResizableController;
     51 
     52     @Override
     53     public void start() {
     54         mWindowManager = new DividerWindowManager(mContext);
     55         update(mContext.getResources().getConfiguration());
     56         putComponent(Divider.class, this);
     57         mDockDividerVisibilityListener = new DockDividerVisibilityListener();
     58         SystemServicesProxy ssp = Recents.getSystemServices();
     59         ssp.registerDockedStackListener(mDockDividerVisibilityListener);
     60         mForcedResizableController = new ForcedResizableInfoActivityController(mContext);
     61         EventBus.getDefault().register(this);
     62     }
     63 
     64     @Override
     65     protected void onConfigurationChanged(Configuration newConfig) {
     66         super.onConfigurationChanged(newConfig);
     67         update(newConfig);
     68     }
     69 
     70     public DividerView getView() {
     71         return mView;
     72     }
     73 
     74     public boolean isMinimized() {
     75         return mMinimized;
     76     }
     77 
     78     public boolean isHomeStackResizable() {
     79         return mHomeStackResizable;
     80     }
     81 
     82     private void addDivider(Configuration configuration) {
     83         mView = (DividerView)
     84                 LayoutInflater.from(mContext).inflate(R.layout.docked_stack_divider, null);
     85         mView.injectDependencies(mWindowManager, mDividerState);
     86         mView.setVisibility(mVisible ? View.VISIBLE : View.INVISIBLE);
     87         mView.setMinimizedDockStack(mMinimized, mHomeStackResizable);
     88         final int size = mContext.getResources().getDimensionPixelSize(
     89                 com.android.internal.R.dimen.docked_stack_divider_thickness);
     90         final boolean landscape = configuration.orientation == ORIENTATION_LANDSCAPE;
     91         final int width = landscape ? size : MATCH_PARENT;
     92         final int height = landscape ? MATCH_PARENT : size;
     93         mWindowManager.add(mView, width, height);
     94     }
     95 
     96     private void removeDivider() {
     97         if (mView != null) {
     98             mView.onDividerRemoved();
     99         }
    100         mWindowManager.remove();
    101     }
    102 
    103     private void update(Configuration configuration) {
    104         removeDivider();
    105         addDivider(configuration);
    106         if (mMinimized) {
    107             mView.setMinimizedDockStack(true, mHomeStackResizable);
    108             updateTouchable();
    109         }
    110     }
    111 
    112     private void updateVisibility(final boolean visible) {
    113         mView.post(new Runnable() {
    114             @Override
    115             public void run() {
    116                 if (mVisible != visible) {
    117                     mVisible = visible;
    118                     mView.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
    119 
    120                     // Update state because animations won't finish.
    121                     mView.setMinimizedDockStack(mMinimized, mHomeStackResizable);
    122                 }
    123             }
    124         });
    125     }
    126 
    127     private void updateMinimizedDockedStack(final boolean minimized, final long animDuration,
    128             final boolean isHomeStackResizable) {
    129         mView.post(new Runnable() {
    130             @Override
    131             public void run() {
    132                 mHomeStackResizable = isHomeStackResizable;
    133                 if (mMinimized != minimized) {
    134                     mMinimized = minimized;
    135                     updateTouchable();
    136                     if (animDuration > 0) {
    137                         mView.setMinimizedDockStack(minimized, animDuration, isHomeStackResizable);
    138                     } else {
    139                         mView.setMinimizedDockStack(minimized, isHomeStackResizable);
    140                     }
    141                 }
    142             }
    143         });
    144     }
    145 
    146     private void notifyDockedStackExistsChanged(final boolean exists) {
    147         mView.post(new Runnable() {
    148             @Override
    149             public void run() {
    150                 mForcedResizableController.notifyDockedStackExistsChanged(exists);
    151             }
    152         });
    153     }
    154 
    155     private void updateTouchable() {
    156         mWindowManager.setTouchable((mHomeStackResizable || !mMinimized) && !mAdjustedForIme);
    157     }
    158 
    159     /**
    160      * Workaround for b/62528361, at the time RecentsDrawnEvent is sent, it may happen before a
    161      * configuration change to the Divider, and internally, the event will be posted to the
    162      * subscriber, or DividerView, which has been removed and prevented from resizing. Instead,
    163      * register the event handler here and proxy the event to the current DividerView.
    164      */
    165     public final void onBusEvent(RecentsDrawnEvent drawnEvent) {
    166         if (mView != null) {
    167             mView.onRecentsDrawn();
    168         }
    169     }
    170 
    171     @Override
    172     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
    173         pw.print("  mVisible="); pw.println(mVisible);
    174         pw.print("  mMinimized="); pw.println(mMinimized);
    175         pw.print("  mAdjustedForIme="); pw.println(mAdjustedForIme);
    176     }
    177 
    178     class DockDividerVisibilityListener extends IDockedStackListener.Stub {
    179 
    180         @Override
    181         public void onDividerVisibilityChanged(boolean visible) throws RemoteException {
    182             updateVisibility(visible);
    183         }
    184 
    185         @Override
    186         public void onDockedStackExistsChanged(boolean exists) throws RemoteException {
    187             notifyDockedStackExistsChanged(exists);
    188         }
    189 
    190         @Override
    191         public void onDockedStackMinimizedChanged(boolean minimized, long animDuration,
    192                 boolean isHomeStackResizable) throws RemoteException {
    193             mHomeStackResizable = isHomeStackResizable;
    194             updateMinimizedDockedStack(minimized, animDuration, isHomeStackResizable);
    195         }
    196 
    197         @Override
    198         public void onAdjustedForImeChanged(boolean adjustedForIme, long animDuration)
    199                 throws RemoteException {
    200             mView.post(() -> {
    201                 if (mAdjustedForIme != adjustedForIme) {
    202                     mAdjustedForIme = adjustedForIme;
    203                     updateTouchable();
    204                     if (!mMinimized) {
    205                         if (animDuration > 0) {
    206                             mView.setAdjustedForIme(adjustedForIme, animDuration);
    207                         } else {
    208                             mView.setAdjustedForIme(adjustedForIme);
    209                         }
    210                     }
    211                 }
    212             });
    213         }
    214 
    215         @Override
    216         public void onDockSideChanged(final int newDockSide) throws RemoteException {
    217             mView.post(() -> mView.notifyDockSideChanged(newDockSide));
    218         }
    219     }
    220 }
    221