Jason Monk | 8a452e9 | 2017-10-31 19:21:47 -0400 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2017 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 androidx.app.slice.widget; |
| 18 | |
Jason Monk | dcb5e2f | 2017-11-15 20:19:43 -0500 | [diff] [blame] | 19 | import static android.app.slice.Slice.HINT_NO_TINT; |
| 20 | import static android.app.slice.Slice.HINT_SELECTED; |
Jason Monk | 0c76d30 | 2017-11-21 14:02:27 -0500 | [diff] [blame] | 21 | import static android.app.slice.SliceItem.FORMAT_ACTION; |
Jason Monk | 0c76d30 | 2017-11-21 14:02:27 -0500 | [diff] [blame] | 22 | import static android.app.slice.SliceItem.FORMAT_IMAGE; |
Amin Shaikh | f2cdc3a | 2018-01-17 09:35:23 -0500 | [diff] [blame] | 23 | import static android.app.slice.SliceItem.FORMAT_INT; |
Jason Monk | 0c76d30 | 2017-11-21 14:02:27 -0500 | [diff] [blame] | 24 | import static android.app.slice.SliceItem.FORMAT_TIMESTAMP; |
| 25 | |
Amin Shaikh | f2cdc3a | 2018-01-17 09:35:23 -0500 | [diff] [blame] | 26 | import static androidx.app.slice.core.SliceHints.EXTRA_SLIDER_VALUE; |
Mady Mellor | c133418 | 2017-11-10 15:50:35 -0800 | [diff] [blame] | 27 | import static androidx.app.slice.core.SliceHints.EXTRA_TOGGLE_STATE; |
Amin Shaikh | f2cdc3a | 2018-01-17 09:35:23 -0500 | [diff] [blame] | 28 | import static androidx.app.slice.core.SliceHints.SUBTYPE_MAX; |
| 29 | import static androidx.app.slice.core.SliceHints.SUBTYPE_PROGRESS; |
Amin Shaikh | bfeddba | 2018-01-10 14:51:13 -0500 | [diff] [blame] | 30 | import static androidx.app.slice.core.SliceHints.SUBTYPE_TOGGLE; |
Mady Mellor | 238b9b6 | 2018-01-09 16:15:40 -0800 | [diff] [blame] | 31 | import static androidx.app.slice.widget.SliceView.MODE_LARGE; |
| 32 | import static androidx.app.slice.widget.SliceView.MODE_SMALL; |
Mady Mellor | c133418 | 2017-11-10 15:50:35 -0800 | [diff] [blame] | 33 | |
Jason Monk | 2a7d0fc | 2017-11-15 10:10:24 -0500 | [diff] [blame] | 34 | import android.annotation.TargetApi; |
Mady Mellor | db8aa8c | 2017-11-08 14:26:17 -0800 | [diff] [blame] | 35 | import android.app.PendingIntent; |
Jason Monk | 8a452e9 | 2017-10-31 19:21:47 -0400 | [diff] [blame] | 36 | import android.app.PendingIntent.CanceledException; |
Jason Monk | 8a452e9 | 2017-10-31 19:21:47 -0400 | [diff] [blame] | 37 | import android.content.Context; |
Mady Mellor | db8aa8c | 2017-11-08 14:26:17 -0800 | [diff] [blame] | 38 | import android.content.Intent; |
Mady Mellor | c133418 | 2017-11-10 15:50:35 -0800 | [diff] [blame] | 39 | import android.graphics.drawable.Icon; |
Mady Mellor | dc05204 | 2018-01-04 17:11:07 -0800 | [diff] [blame] | 40 | import android.support.annotation.ColorInt; |
Jason Monk | 8a452e9 | 2017-10-31 19:21:47 -0400 | [diff] [blame] | 41 | import android.support.annotation.RestrictTo; |
Mady Mellor | db8aa8c | 2017-11-08 14:26:17 -0800 | [diff] [blame] | 42 | import android.util.Log; |
Jason Monk | 8a452e9 | 2017-10-31 19:21:47 -0400 | [diff] [blame] | 43 | import android.view.View; |
Mady Mellor | 238b9b6 | 2018-01-09 16:15:40 -0800 | [diff] [blame] | 44 | import android.view.ViewGroup; |
Jason Monk | 2a7d0fc | 2017-11-15 10:10:24 -0500 | [diff] [blame] | 45 | import android.widget.CompoundButton; |
Jason Monk | 8a452e9 | 2017-10-31 19:21:47 -0400 | [diff] [blame] | 46 | import android.widget.ImageView; |
| 47 | import android.widget.LinearLayout; |
Amin Shaikh | f2cdc3a | 2018-01-17 09:35:23 -0500 | [diff] [blame] | 48 | import android.widget.ProgressBar; |
| 49 | import android.widget.SeekBar; |
Mady Mellor | db8aa8c | 2017-11-08 14:26:17 -0800 | [diff] [blame] | 50 | import android.widget.Switch; |
Jason Monk | 8a452e9 | 2017-10-31 19:21:47 -0400 | [diff] [blame] | 51 | import android.widget.TextView; |
Mady Mellor | c133418 | 2017-11-10 15:50:35 -0800 | [diff] [blame] | 52 | import android.widget.ToggleButton; |
Jason Monk | 8a452e9 | 2017-10-31 19:21:47 -0400 | [diff] [blame] | 53 | |
Jason Monk | 8a452e9 | 2017-10-31 19:21:47 -0400 | [diff] [blame] | 54 | import java.util.ArrayList; |
Jason Monk | 8a452e9 | 2017-10-31 19:21:47 -0400 | [diff] [blame] | 55 | import java.util.List; |
| 56 | |
Jason Monk | dcb5e2f | 2017-11-15 20:19:43 -0500 | [diff] [blame] | 57 | import androidx.app.slice.Slice; |
| 58 | import androidx.app.slice.SliceItem; |
Jason Monk | 8a452e9 | 2017-10-31 19:21:47 -0400 | [diff] [blame] | 59 | import androidx.app.slice.core.SliceQuery; |
| 60 | import androidx.app.slice.view.R; |
| 61 | |
| 62 | /** |
Mady Mellor | c133418 | 2017-11-10 15:50:35 -0800 | [diff] [blame] | 63 | * Row item is in small template format and can be used to construct list items for use |
| 64 | * with {@link LargeTemplateView}. |
Jason Monk | 8a452e9 | 2017-10-31 19:21:47 -0400 | [diff] [blame] | 65 | * |
| 66 | * @hide |
| 67 | */ |
| 68 | @RestrictTo(RestrictTo.Scope.LIBRARY) |
Jason Monk | 2a7d0fc | 2017-11-15 10:10:24 -0500 | [diff] [blame] | 69 | @TargetApi(23) |
Mady Mellor | dc05204 | 2018-01-04 17:11:07 -0800 | [diff] [blame] | 70 | public class RowView extends SliceChildView implements View.OnClickListener { |
Jason Monk | 8a452e9 | 2017-10-31 19:21:47 -0400 | [diff] [blame] | 71 | |
Mady Mellor | c133418 | 2017-11-10 15:50:35 -0800 | [diff] [blame] | 72 | private static final String TAG = "RowView"; |
Jason Monk | 8a452e9 | 2017-10-31 19:21:47 -0400 | [diff] [blame] | 73 | |
Mady Mellor | db8aa8c | 2017-11-08 14:26:17 -0800 | [diff] [blame] | 74 | // The number of items that fit on the right hand side of a small slice |
| 75 | private static final int MAX_END_ITEMS = 3; |
| 76 | |
Jason Monk | 8a452e9 | 2017-10-31 19:21:47 -0400 | [diff] [blame] | 77 | private LinearLayout mStartContainer; |
Mady Mellor | db8aa8c | 2017-11-08 14:26:17 -0800 | [diff] [blame] | 78 | private LinearLayout mContent; |
| 79 | private TextView mPrimaryText; |
Jason Monk | 8a452e9 | 2017-10-31 19:21:47 -0400 | [diff] [blame] | 80 | private TextView mSecondaryText; |
Mady Mellor | c133418 | 2017-11-10 15:50:35 -0800 | [diff] [blame] | 81 | private View mDivider; |
Amin Shaikh | bfeddba | 2018-01-10 14:51:13 -0500 | [diff] [blame] | 82 | private ArrayList<CompoundButton> mToggles = new ArrayList<>(); |
Jason Monk | 8a452e9 | 2017-10-31 19:21:47 -0400 | [diff] [blame] | 83 | private LinearLayout mEndContainer; |
Amin Shaikh | f2cdc3a | 2018-01-17 09:35:23 -0500 | [diff] [blame] | 84 | private SeekBar mSeekBar; |
| 85 | private ProgressBar mProgressBar; |
Jason Monk | 8a452e9 | 2017-10-31 19:21:47 -0400 | [diff] [blame] | 86 | |
Mady Mellor | dc05204 | 2018-01-04 17:11:07 -0800 | [diff] [blame] | 87 | private boolean mInSmallMode; |
Mady Mellor | 238b9b6 | 2018-01-09 16:15:40 -0800 | [diff] [blame] | 88 | private int mRowIndex; |
| 89 | private RowContent mRowContent; |
Mady Mellor | db8aa8c | 2017-11-08 14:26:17 -0800 | [diff] [blame] | 90 | private SliceItem mRowAction; |
Mady Mellor | dc05204 | 2018-01-04 17:11:07 -0800 | [diff] [blame] | 91 | private boolean mIsHeader; |
Mady Mellor | db8aa8c | 2017-11-08 14:26:17 -0800 | [diff] [blame] | 92 | |
Mady Mellor | dc05204 | 2018-01-04 17:11:07 -0800 | [diff] [blame] | 93 | private int mIconSize; |
| 94 | private int mPadding; |
Mady Mellor | 238b9b6 | 2018-01-09 16:15:40 -0800 | [diff] [blame] | 95 | |
Mady Mellor | c133418 | 2017-11-10 15:50:35 -0800 | [diff] [blame] | 96 | public RowView(Context context) { |
Jason Monk | 8a452e9 | 2017-10-31 19:21:47 -0400 | [diff] [blame] | 97 | super(context); |
Jason Monk | 8a452e9 | 2017-10-31 19:21:47 -0400 | [diff] [blame] | 98 | mIconSize = getContext().getResources().getDimensionPixelSize(R.dimen.abc_slice_icon_size); |
| 99 | mPadding = getContext().getResources().getDimensionPixelSize(R.dimen.abc_slice_padding); |
Mady Mellor | db8aa8c | 2017-11-08 14:26:17 -0800 | [diff] [blame] | 100 | inflate(context, R.layout.abc_slice_small_template, this); |
Jason Monk | 8a452e9 | 2017-10-31 19:21:47 -0400 | [diff] [blame] | 101 | |
Jason Monk | 2a7d0fc | 2017-11-15 10:10:24 -0500 | [diff] [blame] | 102 | mStartContainer = (LinearLayout) findViewById(R.id.icon_frame); |
Mady Mellor | db8aa8c | 2017-11-08 14:26:17 -0800 | [diff] [blame] | 103 | mContent = (LinearLayout) findViewById(android.R.id.content); |
| 104 | mPrimaryText = (TextView) findViewById(android.R.id.title); |
Jason Monk | 8a452e9 | 2017-10-31 19:21:47 -0400 | [diff] [blame] | 105 | mSecondaryText = (TextView) findViewById(android.R.id.summary); |
Mady Mellor | db8aa8c | 2017-11-08 14:26:17 -0800 | [diff] [blame] | 106 | mDivider = findViewById(R.id.divider); |
Jason Monk | 8a452e9 | 2017-10-31 19:21:47 -0400 | [diff] [blame] | 107 | mEndContainer = (LinearLayout) findViewById(android.R.id.widget_frame); |
Amin Shaikh | f2cdc3a | 2018-01-17 09:35:23 -0500 | [diff] [blame] | 108 | mSeekBar = (SeekBar) findViewById(R.id.seek_bar); |
| 109 | mProgressBar = (ProgressBar) findViewById(R.id.progress_bar); |
Jason Monk | 8a452e9 | 2017-10-31 19:21:47 -0400 | [diff] [blame] | 110 | } |
| 111 | |
| 112 | @Override |
| 113 | public @SliceView.SliceMode int getMode() { |
Mady Mellor | 238b9b6 | 2018-01-09 16:15:40 -0800 | [diff] [blame] | 114 | return mInSmallMode ? MODE_SMALL : MODE_LARGE; |
Jason Monk | 8a452e9 | 2017-10-31 19:21:47 -0400 | [diff] [blame] | 115 | } |
| 116 | |
| 117 | @Override |
Mady Mellor | dc05204 | 2018-01-04 17:11:07 -0800 | [diff] [blame] | 118 | public void setTint(@ColorInt int tintColor) { |
| 119 | super.setTint(tintColor); |
| 120 | if (mRowContent != null) { |
| 121 | // TODO -- can be smarter about this |
| 122 | resetView(); |
| 123 | populateViews(); |
| 124 | } |
Mady Mellor | 238b9b6 | 2018-01-09 16:15:40 -0800 | [diff] [blame] | 125 | } |
| 126 | |
Mady Mellor | c133418 | 2017-11-10 15:50:35 -0800 | [diff] [blame] | 127 | /** |
| 128 | * This is called when RowView is being used as a component in a large template. |
| 129 | */ |
Jason Monk | 8a452e9 | 2017-10-31 19:21:47 -0400 | [diff] [blame] | 130 | @Override |
Mady Mellor | 238b9b6 | 2018-01-09 16:15:40 -0800 | [diff] [blame] | 131 | public void setSliceItem(SliceItem slice, boolean isHeader, int index, |
| 132 | SliceView.SliceObserver observer) { |
Mady Mellor | dc05204 | 2018-01-04 17:11:07 -0800 | [diff] [blame] | 133 | mInSmallMode = false; |
Mady Mellor | 238b9b6 | 2018-01-09 16:15:40 -0800 | [diff] [blame] | 134 | setSliceObserver(observer); |
| 135 | mRowIndex = index; |
Mady Mellor | 71ef84d | 2017-12-11 13:33:36 -0800 | [diff] [blame] | 136 | mIsHeader = isHeader; |
Mady Mellor | dc05204 | 2018-01-04 17:11:07 -0800 | [diff] [blame] | 137 | mRowContent = new RowContent(slice, !mIsHeader /* showStartItem */); |
| 138 | populateViews(); |
Mady Mellor | db8aa8c | 2017-11-08 14:26:17 -0800 | [diff] [blame] | 139 | } |
Jason Monk | 2a7d0fc | 2017-11-15 10:10:24 -0500 | [diff] [blame] | 140 | |
Mady Mellor | c133418 | 2017-11-10 15:50:35 -0800 | [diff] [blame] | 141 | /** |
| 142 | * This is called when RowView is being used as a small template. |
| 143 | */ |
Mady Mellor | db8aa8c | 2017-11-08 14:26:17 -0800 | [diff] [blame] | 144 | @Override |
Jason Monk | 8a452e9 | 2017-10-31 19:21:47 -0400 | [diff] [blame] | 145 | public void setSlice(Slice slice) { |
Mady Mellor | 71ef84d | 2017-12-11 13:33:36 -0800 | [diff] [blame] | 146 | mInSmallMode = true; |
Mady Mellor | dc05204 | 2018-01-04 17:11:07 -0800 | [diff] [blame] | 147 | mRowIndex = 0; |
| 148 | mIsHeader = true; |
Mady Mellor | 6b5cd61 | 2017-12-14 11:36:59 -0800 | [diff] [blame] | 149 | ListContent lc = new ListContent(slice); |
Mady Mellor | dc05204 | 2018-01-04 17:11:07 -0800 | [diff] [blame] | 150 | mRowContent = new RowContent(lc.getSummaryItem(), false /* showStartItem */); |
| 151 | populateViews(); |
Jason Monk | 8a452e9 | 2017-10-31 19:21:47 -0400 | [diff] [blame] | 152 | } |
| 153 | |
Mady Mellor | dc05204 | 2018-01-04 17:11:07 -0800 | [diff] [blame] | 154 | private void populateViews() { |
Mady Mellor | df26970 | 2017-12-20 15:40:00 -0800 | [diff] [blame] | 155 | resetView(); |
Mady Mellor | 6b5cd61 | 2017-12-14 11:36:59 -0800 | [diff] [blame] | 156 | boolean showStart = false; |
| 157 | final SliceItem startItem = mRowContent.getStartItem(); |
| 158 | if (startItem != null) { |
Mady Mellor | 238b9b6 | 2018-01-09 16:15:40 -0800 | [diff] [blame] | 159 | final EventInfo info = new EventInfo(getMode(), |
| 160 | EventInfo.ACTION_TYPE_BUTTON, |
| 161 | EventInfo.ROW_TYPE_LIST, mRowIndex); |
| 162 | info.setPosition(EventInfo.POSITION_START, 0, 1); |
Mady Mellor | dc05204 | 2018-01-04 17:11:07 -0800 | [diff] [blame] | 163 | showStart = addItem(startItem, mTintColor, true /* isStart */, 0 /* padding */, info); |
Mady Mellor | db8aa8c | 2017-11-08 14:26:17 -0800 | [diff] [blame] | 164 | } |
Mady Mellor | 6b5cd61 | 2017-12-14 11:36:59 -0800 | [diff] [blame] | 165 | mStartContainer.setVisibility(showStart ? View.VISIBLE : View.GONE); |
Mady Mellor | db8aa8c | 2017-11-08 14:26:17 -0800 | [diff] [blame] | 166 | |
Mady Mellor | 6b5cd61 | 2017-12-14 11:36:59 -0800 | [diff] [blame] | 167 | final SliceItem titleItem = mRowContent.getTitleItem(); |
Mady Mellor | db8aa8c | 2017-11-08 14:26:17 -0800 | [diff] [blame] | 168 | if (titleItem != null) { |
| 169 | mPrimaryText.setText(titleItem.getText()); |
| 170 | } |
| 171 | mPrimaryText.setVisibility(titleItem != null ? View.VISIBLE : View.GONE); |
Mady Mellor | 6b5cd61 | 2017-12-14 11:36:59 -0800 | [diff] [blame] | 172 | |
| 173 | final SliceItem subTitle = mRowContent.getSubtitleItem(); |
Mady Mellor | db8aa8c | 2017-11-08 14:26:17 -0800 | [diff] [blame] | 174 | if (subTitle != null) { |
| 175 | mSecondaryText.setText(subTitle.getText()); |
| 176 | } |
| 177 | mSecondaryText.setVisibility(subTitle != null ? View.VISIBLE : View.GONE); |
| 178 | |
Amin Shaikh | f2cdc3a | 2018-01-17 09:35:23 -0500 | [diff] [blame] | 179 | final SliceItem slider = mRowContent.getSlider(); |
| 180 | if (slider != null) { |
| 181 | addSlider(slider); |
| 182 | return; |
| 183 | } |
| 184 | |
Mady Mellor | 6b5cd61 | 2017-12-14 11:36:59 -0800 | [diff] [blame] | 185 | mRowAction = mRowContent.getContentIntent(); |
Amin Shaikh | bfeddba | 2018-01-10 14:51:13 -0500 | [diff] [blame] | 186 | ArrayList<SliceItem> endItems = mRowContent.getEndItems(); |
| 187 | if (endItems.isEmpty()) { |
Mady Mellor | db8aa8c | 2017-11-08 14:26:17 -0800 | [diff] [blame] | 188 | return; |
| 189 | } |
Mady Mellor | 6b5cd61 | 2017-12-14 11:36:59 -0800 | [diff] [blame] | 190 | |
| 191 | // If we're here we might be able to show end items |
Amin Shaikh | bfeddba | 2018-01-10 14:51:13 -0500 | [diff] [blame] | 192 | int itemCount = 0; |
| 193 | // Prefer to show actions as end items if possible; fall back to the first format type. |
| 194 | String desiredFormat = mRowContent.endItemsContainAction() |
| 195 | ? FORMAT_ACTION : endItems.get(0).getFormat(); |
| 196 | boolean firstItemIsADefaultToggle = false; |
| 197 | for (int i = 0; i < endItems.size(); i++) { |
| 198 | final SliceItem endItem = endItems.get(i); |
| 199 | final String endFormat = endItem.getFormat(); |
| 200 | // Only show one type of format at the end of the slice, use whatever is first |
| 201 | if (itemCount <= MAX_END_ITEMS |
| 202 | && (desiredFormat.equals(endFormat) |
| 203 | || FORMAT_TIMESTAMP.equals(endFormat))) { |
| 204 | final EventInfo info = new EventInfo(getMode(), |
| 205 | EventInfo.ACTION_TYPE_BUTTON, |
| 206 | EventInfo.ROW_TYPE_LIST, mRowIndex); |
| 207 | info.setPosition(EventInfo.POSITION_END, i, |
| 208 | Math.min(endItems.size(), MAX_END_ITEMS)); |
Mady Mellor | dc05204 | 2018-01-04 17:11:07 -0800 | [diff] [blame] | 209 | if (addItem(endItem, mTintColor, false /* isStart */, mPadding, info)) { |
Amin Shaikh | bfeddba | 2018-01-10 14:51:13 -0500 | [diff] [blame] | 210 | itemCount++; |
| 211 | if (itemCount == 1) { |
| 212 | firstItemIsADefaultToggle = !mToggles.isEmpty() |
| 213 | && SliceQuery.find(endItem.getSlice(), FORMAT_IMAGE) == null; |
Jason Monk | 2a7d0fc | 2017-11-15 10:10:24 -0500 | [diff] [blame] | 214 | } |
Jason Monk | 8a452e9 | 2017-10-31 19:21:47 -0400 | [diff] [blame] | 215 | } |
| 216 | } |
Amin Shaikh | bfeddba | 2018-01-10 14:51:13 -0500 | [diff] [blame] | 217 | } |
| 218 | |
| 219 | boolean hasRowAction = mRowAction != null; |
| 220 | boolean hasEndItemAction = FORMAT_ACTION.contentEquals(desiredFormat); |
| 221 | // If there is a row action and the first end item is a default toggle, show the divider. |
| 222 | mDivider.setVisibility(hasRowAction && firstItemIsADefaultToggle |
| 223 | ? View.VISIBLE : View.GONE); |
| 224 | if (hasRowAction) { |
| 225 | if (itemCount > 0 && hasEndItemAction) { |
| 226 | setViewClickable(mContent, true); |
| 227 | } else { |
| 228 | setViewClickable(this, true); |
| 229 | } |
| 230 | } else { |
| 231 | // If the only end item is an action, make the whole row clickable. |
| 232 | if (mRowContent.endItemsContainAction() && itemCount == 1) { |
| 233 | setViewClickable(this, true); |
Mady Mellor | 6b5cd61 | 2017-12-14 11:36:59 -0800 | [diff] [blame] | 234 | } |
Mady Mellor | db8aa8c | 2017-11-08 14:26:17 -0800 | [diff] [blame] | 235 | } |
Jason Monk | 8a452e9 | 2017-10-31 19:21:47 -0400 | [diff] [blame] | 236 | } |
| 237 | |
Amin Shaikh | f2cdc3a | 2018-01-17 09:35:23 -0500 | [diff] [blame] | 238 | private void addSlider(final SliceItem slider) { |
| 239 | final ProgressBar progressBar; |
| 240 | if (FORMAT_ACTION.equals(slider.getFormat())) { |
| 241 | // Seek bar |
| 242 | progressBar = mSeekBar; |
| 243 | mSeekBar.setVisibility(View.VISIBLE); |
| 244 | SliceItem thumb = SliceQuery.find(slider, FORMAT_IMAGE); |
| 245 | if (thumb != null) { |
| 246 | mSeekBar.setThumb(thumb.getIcon().loadDrawable(getContext())); |
| 247 | } |
| 248 | mSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { |
| 249 | @Override |
| 250 | public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { |
| 251 | try { |
| 252 | PendingIntent pi = slider.getAction(); |
| 253 | Intent i = new Intent().putExtra(EXTRA_SLIDER_VALUE, progress); |
| 254 | // TODO: sending this PendingIntent should be rate limited. |
| 255 | pi.send(getContext(), 0, i, null, null); |
| 256 | } catch (CanceledException e) { } |
| 257 | } |
| 258 | |
| 259 | @Override |
| 260 | public void onStartTrackingTouch(SeekBar seekBar) { } |
| 261 | |
| 262 | @Override |
| 263 | public void onStopTrackingTouch(SeekBar seekBar) { } |
| 264 | }); |
| 265 | } else { |
| 266 | // Progress bar |
| 267 | progressBar = mProgressBar; |
| 268 | mProgressBar.setVisibility(View.VISIBLE); |
| 269 | } |
| 270 | SliceItem max = SliceQuery.findSubtype(slider, FORMAT_INT, SUBTYPE_MAX); |
| 271 | if (max != null) { |
| 272 | progressBar.setMax(max.getInt()); |
| 273 | } |
| 274 | SliceItem progress = SliceQuery.findSubtype(slider, FORMAT_INT, SUBTYPE_PROGRESS); |
| 275 | if (progress != null) { |
| 276 | progressBar.setProgress(progress.getInt()); |
| 277 | } |
| 278 | } |
| 279 | |
Mady Mellor | db8aa8c | 2017-11-08 14:26:17 -0800 | [diff] [blame] | 280 | /** |
Amin Shaikh | bfeddba | 2018-01-10 14:51:13 -0500 | [diff] [blame] | 281 | * Add a toggle view to container. |
Mady Mellor | db8aa8c | 2017-11-08 14:26:17 -0800 | [diff] [blame] | 282 | */ |
Amin Shaikh | bfeddba | 2018-01-10 14:51:13 -0500 | [diff] [blame] | 283 | private void addToggle(final SliceItem toggleItem, int color, ViewGroup container) { |
Mady Mellor | c133418 | 2017-11-10 15:50:35 -0800 | [diff] [blame] | 284 | // Check if this is a custom toggle |
| 285 | Icon checkedIcon = null; |
| 286 | List<SliceItem> sliceItems = toggleItem.getSlice().getItems(); |
| 287 | if (sliceItems.size() > 0) { |
| 288 | checkedIcon = FORMAT_IMAGE.equals(sliceItems.get(0).getFormat()) |
| 289 | ? sliceItems.get(0).getIcon() |
| 290 | : null; |
| 291 | } |
Amin Shaikh | bfeddba | 2018-01-10 14:51:13 -0500 | [diff] [blame] | 292 | final CompoundButton toggle; |
Mady Mellor | c133418 | 2017-11-10 15:50:35 -0800 | [diff] [blame] | 293 | if (checkedIcon != null) { |
| 294 | if (color != -1) { |
Mady Mellor | dc05204 | 2018-01-04 17:11:07 -0800 | [diff] [blame] | 295 | // TODO - Should custom toggle buttons be tinted? What if the app wants diff |
| 296 | // colors per state? |
Mady Mellor | c133418 | 2017-11-10 15:50:35 -0800 | [diff] [blame] | 297 | checkedIcon.setTint(color); |
| 298 | } |
Amin Shaikh | bfeddba | 2018-01-10 14:51:13 -0500 | [diff] [blame] | 299 | toggle = new ToggleButton(getContext()); |
| 300 | ((ToggleButton) toggle).setTextOff(""); |
| 301 | ((ToggleButton) toggle).setTextOn(""); |
| 302 | toggle.setBackground(checkedIcon.loadDrawable(getContext())); |
| 303 | container.addView(toggle); |
| 304 | LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) toggle.getLayoutParams(); |
Mady Mellor | c133418 | 2017-11-10 15:50:35 -0800 | [diff] [blame] | 305 | lp.width = mIconSize; |
| 306 | lp.height = mIconSize; |
| 307 | } else { |
Amin Shaikh | bfeddba | 2018-01-10 14:51:13 -0500 | [diff] [blame] | 308 | toggle = new Switch(getContext()); |
| 309 | container.addView(toggle); |
Mady Mellor | c133418 | 2017-11-10 15:50:35 -0800 | [diff] [blame] | 310 | } |
Amin Shaikh | bfeddba | 2018-01-10 14:51:13 -0500 | [diff] [blame] | 311 | toggle.setChecked(SliceQuery.hasHints(toggleItem.getSlice(), HINT_SELECTED)); |
| 312 | toggle.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { |
Jason Monk | 2a7d0fc | 2017-11-15 10:10:24 -0500 | [diff] [blame] | 313 | @Override |
| 314 | public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { |
| 315 | try { |
| 316 | PendingIntent pi = toggleItem.getAction(); |
Mady Mellor | c133418 | 2017-11-10 15:50:35 -0800 | [diff] [blame] | 317 | Intent i = new Intent().putExtra(EXTRA_TOGGLE_STATE, isChecked); |
Jason Monk | 2a7d0fc | 2017-11-15 10:10:24 -0500 | [diff] [blame] | 318 | pi.send(getContext(), 0, i, null, null); |
Mady Mellor | 238b9b6 | 2018-01-09 16:15:40 -0800 | [diff] [blame] | 319 | if (mObserver != null) { |
| 320 | final EventInfo info = new EventInfo(getMode(), |
| 321 | EventInfo.ACTION_TYPE_TOGGLE, |
| 322 | EventInfo.ROW_TYPE_LIST, mRowIndex); |
| 323 | info.state = isChecked ? EventInfo.STATE_ON : EventInfo.STATE_OFF; |
| 324 | mObserver.onSliceAction(info, toggleItem); |
| 325 | } |
Jason Monk | 2a7d0fc | 2017-11-15 10:10:24 -0500 | [diff] [blame] | 326 | } catch (CanceledException e) { |
Amin Shaikh | bfeddba | 2018-01-10 14:51:13 -0500 | [diff] [blame] | 327 | toggle.setSelected(!isChecked); |
Jason Monk | 2a7d0fc | 2017-11-15 10:10:24 -0500 | [diff] [blame] | 328 | } |
Mady Mellor | db8aa8c | 2017-11-08 14:26:17 -0800 | [diff] [blame] | 329 | } |
| 330 | }); |
Amin Shaikh | bfeddba | 2018-01-10 14:51:13 -0500 | [diff] [blame] | 331 | mToggles.add(toggle); |
Jason Monk | 8a452e9 | 2017-10-31 19:21:47 -0400 | [diff] [blame] | 332 | } |
| 333 | |
| 334 | /** |
Mady Mellor | c133418 | 2017-11-10 15:50:35 -0800 | [diff] [blame] | 335 | * Adds simple items to a container. Simple items include actions with icons, images, or |
| 336 | * timestamps. |
Jason Monk | 8a452e9 | 2017-10-31 19:21:47 -0400 | [diff] [blame] | 337 | */ |
Mady Mellor | 238b9b6 | 2018-01-09 16:15:40 -0800 | [diff] [blame] | 338 | private boolean addItem(SliceItem sliceItem, int color, boolean isStart, int padding, |
| 339 | final EventInfo info) { |
Jason Monk | 8a452e9 | 2017-10-31 19:21:47 -0400 | [diff] [blame] | 340 | SliceItem image = null; |
| 341 | SliceItem action = null; |
Mady Mellor | c133418 | 2017-11-10 15:50:35 -0800 | [diff] [blame] | 342 | SliceItem timeStamp = null; |
Mady Mellor | 238b9b6 | 2018-01-09 16:15:40 -0800 | [diff] [blame] | 343 | ViewGroup container = isStart ? mStartContainer : mEndContainer; |
Amin Shaikh | bfeddba | 2018-01-10 14:51:13 -0500 | [diff] [blame] | 344 | if (FORMAT_ACTION.equals(sliceItem.getFormat())) { |
| 345 | if (SliceQuery.hasHints(sliceItem.getSlice(), SUBTYPE_TOGGLE)) { |
| 346 | addToggle(sliceItem, color, container); |
| 347 | return true; |
| 348 | } |
Jason Monk | 0c76d30 | 2017-11-21 14:02:27 -0500 | [diff] [blame] | 349 | image = SliceQuery.find(sliceItem.getSlice(), FORMAT_IMAGE); |
Mady Mellor | c133418 | 2017-11-10 15:50:35 -0800 | [diff] [blame] | 350 | timeStamp = SliceQuery.find(sliceItem.getSlice(), FORMAT_TIMESTAMP); |
Jason Monk | 8a452e9 | 2017-10-31 19:21:47 -0400 | [diff] [blame] | 351 | action = sliceItem; |
Jason Monk | 0c76d30 | 2017-11-21 14:02:27 -0500 | [diff] [blame] | 352 | } else if (FORMAT_IMAGE.equals(sliceItem.getFormat())) { |
Jason Monk | 8a452e9 | 2017-10-31 19:21:47 -0400 | [diff] [blame] | 353 | image = sliceItem; |
Mady Mellor | c133418 | 2017-11-10 15:50:35 -0800 | [diff] [blame] | 354 | } else if (FORMAT_TIMESTAMP.equals(sliceItem.getFormat())) { |
| 355 | timeStamp = sliceItem; |
Jason Monk | 8a452e9 | 2017-10-31 19:21:47 -0400 | [diff] [blame] | 356 | } |
Mady Mellor | c133418 | 2017-11-10 15:50:35 -0800 | [diff] [blame] | 357 | View addedView = null; |
Jason Monk | 8a452e9 | 2017-10-31 19:21:47 -0400 | [diff] [blame] | 358 | if (image != null) { |
| 359 | ImageView iv = new ImageView(getContext()); |
| 360 | iv.setImageIcon(image.getIcon()); |
Jason Monk | dcb5e2f | 2017-11-15 20:19:43 -0500 | [diff] [blame] | 361 | if (color != -1 && !sliceItem.hasHint(HINT_NO_TINT)) { |
Jason Monk | 8a452e9 | 2017-10-31 19:21:47 -0400 | [diff] [blame] | 362 | iv.setColorFilter(color); |
| 363 | } |
| 364 | container.addView(iv); |
| 365 | LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) iv.getLayoutParams(); |
| 366 | lp.width = mIconSize; |
| 367 | lp.height = mIconSize; |
Mady Mellor | c133418 | 2017-11-10 15:50:35 -0800 | [diff] [blame] | 368 | lp.setMarginStart(padding); |
| 369 | addedView = iv; |
| 370 | } else if (timeStamp != null) { |
| 371 | TextView tv = new TextView(getContext()); |
| 372 | tv.setText(SliceViewUtil.getRelativeTimeString(sliceItem.getTimestamp())); |
| 373 | container.addView(tv); |
| 374 | addedView = tv; |
Jason Monk | 8a452e9 | 2017-10-31 19:21:47 -0400 | [diff] [blame] | 375 | } |
Mady Mellor | c133418 | 2017-11-10 15:50:35 -0800 | [diff] [blame] | 376 | if (action != null && addedView != null) { |
| 377 | final SliceItem sliceAction = action; |
| 378 | addedView.setOnClickListener(new View.OnClickListener() { |
| 379 | @Override |
| 380 | public void onClick(View v) { |
Mady Mellor | 238b9b6 | 2018-01-09 16:15:40 -0800 | [diff] [blame] | 381 | try { |
| 382 | sliceAction.getAction().send(); |
| 383 | if (mObserver != null) { |
| 384 | mObserver.onSliceAction(info, sliceAction); |
Mady Mellor | c133418 | 2017-11-10 15:50:35 -0800 | [diff] [blame] | 385 | } |
Mady Mellor | 238b9b6 | 2018-01-09 16:15:40 -0800 | [diff] [blame] | 386 | } catch (CanceledException e) { |
| 387 | e.printStackTrace(); |
| 388 | } |
Mady Mellor | c133418 | 2017-11-10 15:50:35 -0800 | [diff] [blame] | 389 | } |
| 390 | }); |
| 391 | addedView.setBackground(SliceViewUtil.getDrawable(getContext(), |
| 392 | android.R.attr.selectableItemBackground)); |
| 393 | } |
| 394 | return addedView != null; |
Jason Monk | 8a452e9 | 2017-10-31 19:21:47 -0400 | [diff] [blame] | 395 | } |
| 396 | |
Mady Mellor | db8aa8c | 2017-11-08 14:26:17 -0800 | [diff] [blame] | 397 | @Override |
| 398 | public void onClick(View view) { |
Jason Monk | 0c76d30 | 2017-11-21 14:02:27 -0500 | [diff] [blame] | 399 | if (mRowAction != null && FORMAT_ACTION.equals(mRowAction.getFormat())) { |
Mady Mellor | c133418 | 2017-11-10 15:50:35 -0800 | [diff] [blame] | 400 | // Check for a row action |
Mady Mellor | 238b9b6 | 2018-01-09 16:15:40 -0800 | [diff] [blame] | 401 | try { |
| 402 | mRowAction.getAction().send(); |
| 403 | if (mObserver != null) { |
| 404 | EventInfo info = new EventInfo(getMode(), EventInfo.ACTION_TYPE_CONTENT, |
| 405 | EventInfo.ROW_TYPE_LIST, mRowIndex); |
| 406 | mObserver.onSliceAction(info, mRowAction); |
Mady Mellor | db8aa8c | 2017-11-08 14:26:17 -0800 | [diff] [blame] | 407 | } |
Mady Mellor | 238b9b6 | 2018-01-09 16:15:40 -0800 | [diff] [blame] | 408 | } catch (CanceledException e) { |
| 409 | Log.w(TAG, "PendingIntent for slice cannot be sent", e); |
| 410 | } |
Amin Shaikh | bfeddba | 2018-01-10 14:51:13 -0500 | [diff] [blame] | 411 | } else if (mToggles.size() == 1) { |
| 412 | // If there is only one toggle and no row action, just toggle it. |
| 413 | mToggles.get(0).toggle(); |
Mady Mellor | db8aa8c | 2017-11-08 14:26:17 -0800 | [diff] [blame] | 414 | } |
| 415 | } |
| 416 | |
Mady Mellor | df26970 | 2017-12-20 15:40:00 -0800 | [diff] [blame] | 417 | private void setViewClickable(View layout, boolean isClickable) { |
| 418 | layout.setOnClickListener(isClickable ? this : null); |
| 419 | layout.setBackground(isClickable ? SliceViewUtil.getDrawable(getContext(), |
| 420 | android.R.attr.selectableItemBackground) : null); |
Mady Mellor | 238b9b6 | 2018-01-09 16:15:40 -0800 | [diff] [blame] | 421 | layout.setClickable(isClickable); |
Jason Monk | 8a452e9 | 2017-10-31 19:21:47 -0400 | [diff] [blame] | 422 | } |
| 423 | |
Mady Mellor | df26970 | 2017-12-20 15:40:00 -0800 | [diff] [blame] | 424 | @Override |
| 425 | public void resetView() { |
| 426 | setViewClickable(this, false); |
| 427 | setViewClickable(mContent, false); |
Jason Monk | 8a452e9 | 2017-10-31 19:21:47 -0400 | [diff] [blame] | 428 | mStartContainer.removeAllViews(); |
| 429 | mEndContainer.removeAllViews(); |
Mady Mellor | db8aa8c | 2017-11-08 14:26:17 -0800 | [diff] [blame] | 430 | mPrimaryText.setText(null); |
Jason Monk | 8a452e9 | 2017-10-31 19:21:47 -0400 | [diff] [blame] | 431 | mSecondaryText.setText(null); |
Amin Shaikh | bfeddba | 2018-01-10 14:51:13 -0500 | [diff] [blame] | 432 | mToggles.clear(); |
Mady Mellor | df26970 | 2017-12-20 15:40:00 -0800 | [diff] [blame] | 433 | mRowAction = null; |
Mady Mellor | c133418 | 2017-11-10 15:50:35 -0800 | [diff] [blame] | 434 | mDivider.setVisibility(View.GONE); |
Amin Shaikh | f2cdc3a | 2018-01-17 09:35:23 -0500 | [diff] [blame] | 435 | mSeekBar.setVisibility(View.GONE); |
| 436 | mProgressBar.setVisibility(View.GONE); |
Jason Monk | 8a452e9 | 2017-10-31 19:21:47 -0400 | [diff] [blame] | 437 | } |
| 438 | } |