1 /* 2 * Copyright (C) 2019 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.globalactions; 18 19 import static com.android.systemui.util.leak.RotationUtils.ROTATION_LANDSCAPE; 20 import static com.android.systemui.util.leak.RotationUtils.ROTATION_NONE; 21 import static com.android.systemui.util.leak.RotationUtils.ROTATION_SEASCAPE; 22 23 import android.content.Context; 24 import android.util.AttributeSet; 25 import android.view.View; 26 import android.view.ViewGroup; 27 28 import com.android.internal.annotations.VisibleForTesting; 29 30 /** 31 * Grid-based implementation of the button layout created by the global actions dialog. 32 */ 33 public class GlobalActionsGridLayout extends GlobalActionsLayout { GlobalActionsGridLayout(Context context, AttributeSet attrs)34 public GlobalActionsGridLayout(Context context, AttributeSet attrs) { 35 super(context, attrs); 36 } 37 38 @VisibleForTesting setupListView()39 protected void setupListView() { 40 ListGridLayout listView = getListView(); 41 listView.setExpectedCount(mAdapter.countListItems()); 42 listView.setReverseSublists(shouldReverseSublists()); 43 listView.setReverseItems(shouldReverseListItems()); 44 listView.setSwapRowsAndColumns(shouldSwapRowsAndColumns()); 45 } 46 47 @Override onUpdateList()48 public void onUpdateList() { 49 setupListView(); 50 super.onUpdateList(); 51 updateSeparatedItemSize(); 52 } 53 54 /** 55 * If the separated view contains only one item, expand the bounds of that item to take up the 56 * entire view, so that the whole thing is touch-able. 57 */ 58 @VisibleForTesting updateSeparatedItemSize()59 protected void updateSeparatedItemSize() { 60 ViewGroup separated = getSeparatedView(); 61 if (separated.getChildCount() == 0) { 62 return; 63 } 64 View firstChild = separated.getChildAt(0); 65 ViewGroup.LayoutParams childParams = firstChild.getLayoutParams(); 66 67 if (separated.getChildCount() == 1) { 68 childParams.width = ViewGroup.LayoutParams.MATCH_PARENT; 69 childParams.height = ViewGroup.LayoutParams.MATCH_PARENT; 70 } else { 71 childParams.width = ViewGroup.LayoutParams.WRAP_CONTENT; 72 childParams.height = ViewGroup.LayoutParams.WRAP_CONTENT; 73 } 74 } 75 76 @Override getListView()77 protected ListGridLayout getListView() { 78 return (ListGridLayout) super.getListView(); 79 } 80 81 @Override removeAllListViews()82 protected void removeAllListViews() { 83 ListGridLayout list = getListView(); 84 if (list != null) { 85 list.removeAllItems(); 86 } 87 } 88 89 @Override addToListView(View v, boolean reverse)90 protected void addToListView(View v, boolean reverse) { 91 ListGridLayout list = getListView(); 92 if (list != null) { 93 list.addItem(v); 94 } 95 } 96 97 @Override removeAllItems()98 public void removeAllItems() { 99 ViewGroup separatedList = getSeparatedView(); 100 ListGridLayout list = getListView(); 101 if (separatedList != null) { 102 separatedList.removeAllViews(); 103 } 104 if (list != null) { 105 list.removeAllItems(); 106 } 107 } 108 109 /** 110 * Determines whether the ListGridLayout should fill sublists in the reverse order. 111 * Used to account for sublist ordering changing between landscape and seascape views. 112 */ 113 @VisibleForTesting shouldReverseSublists()114 protected boolean shouldReverseSublists() { 115 if (getCurrentRotation() == ROTATION_SEASCAPE) { 116 return true; 117 } 118 return false; 119 } 120 121 /** 122 * Determines whether the ListGridLayout should fill rows first instead of columns. 123 * Used to account for vertical/horizontal changes due to landscape or seascape rotations. 124 */ 125 @VisibleForTesting shouldSwapRowsAndColumns()126 protected boolean shouldSwapRowsAndColumns() { 127 if (getCurrentRotation() == ROTATION_NONE) { 128 return false; 129 } 130 return true; 131 } 132 133 @Override shouldReverseListItems()134 protected boolean shouldReverseListItems() { 135 int rotation = getCurrentRotation(); 136 boolean reverse = false; // should we add items to parents in the reverse order? 137 if (rotation == ROTATION_NONE 138 || rotation == ROTATION_SEASCAPE) { 139 reverse = !reverse; // if we're in portrait or seascape, reverse items 140 } 141 if (getCurrentLayoutDirection() == View.LAYOUT_DIRECTION_RTL) { 142 reverse = !reverse; // if we're in an RTL language, reverse items (again) 143 } 144 return reverse; 145 } 146 147 @VisibleForTesting getAnimationDistance()148 protected float getAnimationDistance() { 149 int rows = getListView().getRowCount(); 150 float gridItemSize = getContext().getResources().getDimension( 151 com.android.systemui.R.dimen.global_actions_grid_item_height); 152 return rows * gridItemSize / 2; 153 } 154 155 @Override getAnimationOffsetX()156 public float getAnimationOffsetX() { 157 switch (getCurrentRotation()) { 158 case ROTATION_LANDSCAPE: 159 return getAnimationDistance(); 160 case ROTATION_SEASCAPE: 161 return -getAnimationDistance(); 162 default: // Portrait 163 return 0; 164 } 165 } 166 167 @Override getAnimationOffsetY()168 public float getAnimationOffsetY() { 169 if (getCurrentRotation() == ROTATION_NONE) { 170 return getAnimationDistance(); 171 } 172 return 0; 173 } 174 } 175