Oli Lan | f98ae93 | 2022-01-17 18:19:36 +0000 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2022 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 | |
Anna Bauza | e95044a | 2024-03-21 20:54:39 +0000 | [diff] [blame^] | 17 | package com.android.settingslib.avatarpicker; |
Oli Lan | f98ae93 | 2022-01-17 18:19:36 +0000 | [diff] [blame] | 18 | |
| 19 | import android.app.Activity; |
Oli Lan | b475112 | 2022-01-18 10:05:36 +0000 | [diff] [blame] | 20 | import android.content.ContentResolver; |
Oli Lan | f98ae93 | 2022-01-17 18:19:36 +0000 | [diff] [blame] | 21 | import android.content.Intent; |
| 22 | import android.content.res.TypedArray; |
| 23 | import android.graphics.Bitmap; |
| 24 | import android.graphics.drawable.BitmapDrawable; |
| 25 | import android.graphics.drawable.Drawable; |
Oli Lan | b475112 | 2022-01-18 10:05:36 +0000 | [diff] [blame] | 26 | import android.net.Uri; |
Oli Lan | f98ae93 | 2022-01-17 18:19:36 +0000 | [diff] [blame] | 27 | import android.os.Bundle; |
Anna Bauza | 6ad6b16 | 2023-10-24 18:33:22 +0000 | [diff] [blame] | 28 | import android.util.Log; |
Oli Lan | f98ae93 | 2022-01-17 18:19:36 +0000 | [diff] [blame] | 29 | import android.view.LayoutInflater; |
| 30 | import android.view.View; |
| 31 | import android.view.ViewGroup; |
| 32 | import android.widget.ImageView; |
| 33 | |
| 34 | import androidx.annotation.NonNull; |
| 35 | import androidx.core.graphics.drawable.RoundedBitmapDrawable; |
| 36 | import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory; |
| 37 | import androidx.recyclerview.widget.GridLayoutManager; |
| 38 | import androidx.recyclerview.widget.RecyclerView; |
| 39 | |
Oli Lan | 4f3a0b8f | 2022-01-21 10:24:34 +0000 | [diff] [blame] | 40 | import com.android.internal.util.UserIcons; |
Oli Lan | f98ae93 | 2022-01-17 18:19:36 +0000 | [diff] [blame] | 41 | |
| 42 | import com.google.android.setupcompat.template.FooterBarMixin; |
| 43 | import com.google.android.setupcompat.template.FooterButton; |
| 44 | import com.google.android.setupdesign.GlifLayout; |
| 45 | import com.google.android.setupdesign.util.ThemeHelper; |
Tetiana Meronyk | 23d6f84 | 2022-09-21 17:19:20 +0000 | [diff] [blame] | 46 | import com.google.android.setupdesign.util.ThemeResolver; |
Oli Lan | f98ae93 | 2022-01-17 18:19:36 +0000 | [diff] [blame] | 47 | |
Oli Lan | 4f3a0b8f | 2022-01-21 10:24:34 +0000 | [diff] [blame] | 48 | import java.util.ArrayList; |
Oli Lan | 735747f | 2022-01-24 15:00:14 +0000 | [diff] [blame] | 49 | import java.util.Arrays; |
Oli Lan | 4f3a0b8f | 2022-01-21 10:24:34 +0000 | [diff] [blame] | 50 | import java.util.List; |
| 51 | |
Oli Lan | f98ae93 | 2022-01-17 18:19:36 +0000 | [diff] [blame] | 52 | /** |
| 53 | * Activity to allow the user to choose a user profile picture. |
Oli Lan | 4f3a0b8f | 2022-01-21 10:24:34 +0000 | [diff] [blame] | 54 | * |
| 55 | * <p>Options are provided to take a photo or choose a photo using the photo picker. In addition, |
| 56 | * preselected avatar images may be provided in the resource array {@code avatar_images}. If |
| 57 | * provided, every element of that array must be a bitmap drawable. |
| 58 | * |
| 59 | * <p>If preselected images are not provided, the default avatar will be shown instead, in a range |
| 60 | * of colors. |
| 61 | * |
| 62 | * <p>This activity should be started with startActivityForResult. If a photo or a preselected image |
| 63 | * is selected, a Uri will be returned in the data field of the result intent. If a colored default |
| 64 | * avatar is selected, the chosen color will be returned as {@code EXTRA_DEFAULT_ICON_TINT_COLOR} |
| 65 | * and the data field will be empty. |
Oli Lan | f98ae93 | 2022-01-17 18:19:36 +0000 | [diff] [blame] | 66 | */ |
| 67 | public class AvatarPickerActivity extends Activity { |
| 68 | |
Oli Lan | b475112 | 2022-01-18 10:05:36 +0000 | [diff] [blame] | 69 | static final String EXTRA_FILE_AUTHORITY = "file_authority"; |
Oli Lan | 4f3a0b8f | 2022-01-21 10:24:34 +0000 | [diff] [blame] | 70 | static final String EXTRA_DEFAULT_ICON_TINT_COLOR = "default_icon_tint_color"; |
| 71 | |
Oli Lan | b475112 | 2022-01-18 10:05:36 +0000 | [diff] [blame] | 72 | private static final String KEY_AWAITING_RESULT = "awaiting_result"; |
| 73 | private static final String KEY_SELECTED_POSITION = "selected_position"; |
| 74 | |
| 75 | private boolean mWaitingForActivityResult; |
Oli Lan | f98ae93 | 2022-01-17 18:19:36 +0000 | [diff] [blame] | 76 | |
| 77 | private FooterButton mDoneButton; |
| 78 | private AvatarAdapter mAdapter; |
| 79 | |
Oli Lan | b475112 | 2022-01-18 10:05:36 +0000 | [diff] [blame] | 80 | private AvatarPhotoController mAvatarPhotoController; |
| 81 | |
Oli Lan | f98ae93 | 2022-01-17 18:19:36 +0000 | [diff] [blame] | 82 | @Override |
| 83 | protected void onCreate(Bundle savedInstanceState) { |
| 84 | super.onCreate(savedInstanceState); |
Tetiana Meronyk | 23d6f84 | 2022-09-21 17:19:20 +0000 | [diff] [blame] | 85 | boolean dayNightEnabled = ThemeHelper.isSetupWizardDayNightEnabled(this); |
| 86 | ThemeResolver themeResolver = |
| 87 | new ThemeResolver.Builder(ThemeResolver.getDefault()) |
| 88 | .setDefaultTheme(ThemeHelper.getSuwDefaultTheme(this)) |
| 89 | .setUseDayNight(true) |
| 90 | .build(); |
| 91 | int themeResId = themeResolver.resolve("", /* suppressDayNight= */ !dayNightEnabled); |
| 92 | setTheme(themeResId); |
Oli Lan | f98ae93 | 2022-01-17 18:19:36 +0000 | [diff] [blame] | 93 | ThemeHelper.trySetDynamicColor(this); |
| 94 | setContentView(R.layout.avatar_picker); |
Oli Lan | b475112 | 2022-01-18 10:05:36 +0000 | [diff] [blame] | 95 | setUpButtons(); |
Oli Lan | f98ae93 | 2022-01-17 18:19:36 +0000 | [diff] [blame] | 96 | |
Oli Lan | f98ae93 | 2022-01-17 18:19:36 +0000 | [diff] [blame] | 97 | RecyclerView recyclerView = findViewById(R.id.avatar_grid); |
Oli Lan | b475112 | 2022-01-18 10:05:36 +0000 | [diff] [blame] | 98 | mAdapter = new AvatarAdapter(); |
| 99 | recyclerView.setAdapter(mAdapter); |
| 100 | recyclerView.setLayoutManager(new GridLayoutManager(this, |
| 101 | getResources().getInteger(R.integer.avatar_picker_columns))); |
| 102 | |
| 103 | restoreState(savedInstanceState); |
| 104 | |
| 105 | mAvatarPhotoController = new AvatarPhotoController( |
Oli Lan | e8e79f8 | 2022-02-24 15:52:13 +0000 | [diff] [blame] | 106 | new AvatarPhotoController.AvatarUiImpl(this), |
| 107 | new AvatarPhotoController.ContextInjectorImpl(this, getFileAuthority()), |
| 108 | mWaitingForActivityResult); |
Oli Lan | b475112 | 2022-01-18 10:05:36 +0000 | [diff] [blame] | 109 | } |
| 110 | |
Anna Bauza | 1ad4dc5 | 2023-04-21 16:17:15 +0000 | [diff] [blame] | 111 | @Override |
| 112 | protected void onResume() { |
| 113 | super.onResume(); |
| 114 | mAdapter.onAdapterResume(); |
| 115 | } |
| 116 | |
Oli Lan | b475112 | 2022-01-18 10:05:36 +0000 | [diff] [blame] | 117 | private void setUpButtons() { |
| 118 | GlifLayout glifLayout = findViewById(R.id.glif_layout); |
Oli Lan | f98ae93 | 2022-01-17 18:19:36 +0000 | [diff] [blame] | 119 | FooterBarMixin mixin = glifLayout.getMixin(FooterBarMixin.class); |
| 120 | |
| 121 | FooterButton secondaryButton = |
| 122 | new FooterButton.Builder(this) |
Oli Lan | b713e27 | 2022-03-10 10:38:10 +0000 | [diff] [blame] | 123 | .setText(getString(android.R.string.cancel)) |
Oli Lan | f98ae93 | 2022-01-17 18:19:36 +0000 | [diff] [blame] | 124 | .setListener(view -> cancel()) |
| 125 | .build(); |
| 126 | |
| 127 | mDoneButton = |
| 128 | new FooterButton.Builder(this) |
Oli Lan | b713e27 | 2022-03-10 10:38:10 +0000 | [diff] [blame] | 129 | .setText(getString(R.string.done)) |
Oli Lan | 4f3a0b8f | 2022-01-21 10:24:34 +0000 | [diff] [blame] | 130 | .setListener(view -> mAdapter.returnSelectionResult()) |
Oli Lan | f98ae93 | 2022-01-17 18:19:36 +0000 | [diff] [blame] | 131 | .build(); |
| 132 | mDoneButton.setEnabled(false); |
| 133 | |
| 134 | mixin.setSecondaryButton(secondaryButton); |
| 135 | mixin.setPrimaryButton(mDoneButton); |
Oli Lan | f98ae93 | 2022-01-17 18:19:36 +0000 | [diff] [blame] | 136 | } |
| 137 | |
Oli Lan | b475112 | 2022-01-18 10:05:36 +0000 | [diff] [blame] | 138 | private String getFileAuthority() { |
| 139 | String authority = getIntent().getStringExtra(EXTRA_FILE_AUTHORITY); |
| 140 | if (authority == null) { |
Anna Bauza | 6ad6b16 | 2023-10-24 18:33:22 +0000 | [diff] [blame] | 141 | Log.e(this.getClass().getName(), "File authority must be provided"); |
| 142 | finish(); |
Oli Lan | b475112 | 2022-01-18 10:05:36 +0000 | [diff] [blame] | 143 | } |
| 144 | return authority; |
| 145 | } |
| 146 | |
| 147 | @Override |
| 148 | protected void onActivityResult(int requestCode, int resultCode, Intent data) { |
| 149 | mWaitingForActivityResult = false; |
| 150 | mAvatarPhotoController.onActivityResult(requestCode, resultCode, data); |
| 151 | } |
| 152 | |
| 153 | @Override |
| 154 | protected void onSaveInstanceState(@NonNull Bundle outState) { |
| 155 | outState.putBoolean(KEY_AWAITING_RESULT, mWaitingForActivityResult); |
| 156 | outState.putInt(KEY_SELECTED_POSITION, mAdapter.mSelectedPosition); |
| 157 | super.onSaveInstanceState(outState); |
| 158 | } |
| 159 | |
| 160 | private void restoreState(Bundle savedInstanceState) { |
| 161 | if (savedInstanceState != null) { |
| 162 | mWaitingForActivityResult = savedInstanceState.getBoolean(KEY_AWAITING_RESULT, false); |
| 163 | mAdapter.mSelectedPosition = |
| 164 | savedInstanceState.getInt(KEY_SELECTED_POSITION, AvatarAdapter.NONE); |
Oli Lan | 0ef54ab | 2022-05-09 15:36:10 +0100 | [diff] [blame] | 165 | mDoneButton.setEnabled(mAdapter.mSelectedPosition != AvatarAdapter.NONE); |
Oli Lan | b475112 | 2022-01-18 10:05:36 +0000 | [diff] [blame] | 166 | } |
| 167 | } |
| 168 | |
| 169 | @Override |
| 170 | public void startActivityForResult(Intent intent, int requestCode) { |
| 171 | mWaitingForActivityResult = true; |
| 172 | super.startActivityForResult(intent, requestCode); |
| 173 | } |
| 174 | |
Oli Lan | 4f3a0b8f | 2022-01-21 10:24:34 +0000 | [diff] [blame] | 175 | void returnUriResult(Uri uri) { |
Oli Lan | b475112 | 2022-01-18 10:05:36 +0000 | [diff] [blame] | 176 | Intent resultData = new Intent(); |
| 177 | resultData.setData(uri); |
| 178 | setResult(RESULT_OK, resultData); |
Oli Lan | f98ae93 | 2022-01-17 18:19:36 +0000 | [diff] [blame] | 179 | finish(); |
| 180 | } |
| 181 | |
Oli Lan | 4f3a0b8f | 2022-01-21 10:24:34 +0000 | [diff] [blame] | 182 | void returnColorResult(int color) { |
| 183 | Intent resultData = new Intent(); |
| 184 | resultData.putExtra(EXTRA_DEFAULT_ICON_TINT_COLOR, color); |
| 185 | setResult(RESULT_OK, resultData); |
| 186 | finish(); |
| 187 | } |
| 188 | |
Oli Lan | f98ae93 | 2022-01-17 18:19:36 +0000 | [diff] [blame] | 189 | private void cancel() { |
| 190 | setResult(RESULT_CANCELED); |
| 191 | finish(); |
| 192 | } |
| 193 | |
| 194 | private class AvatarAdapter extends RecyclerView.Adapter<AvatarViewHolder> { |
| 195 | |
| 196 | private static final int NONE = -1; |
Oli Lan | b475112 | 2022-01-18 10:05:36 +0000 | [diff] [blame] | 197 | |
| 198 | private final int mTakePhotoPosition; |
| 199 | private final int mChoosePhotoPosition; |
| 200 | private final int mPreselectedImageStartPosition; |
Oli Lan | f98ae93 | 2022-01-17 18:19:36 +0000 | [diff] [blame] | 201 | |
Oli Lan | 4f3a0b8f | 2022-01-21 10:24:34 +0000 | [diff] [blame] | 202 | private final List<Drawable> mImageDrawables; |
Oli Lan | 735747f | 2022-01-24 15:00:14 +0000 | [diff] [blame] | 203 | private final List<String> mImageDescriptions; |
Oli Lan | 4f3a0b8f | 2022-01-21 10:24:34 +0000 | [diff] [blame] | 204 | private final TypedArray mPreselectedImages; |
| 205 | private final int[] mUserIconColors; |
Oli Lan | f98ae93 | 2022-01-17 18:19:36 +0000 | [diff] [blame] | 206 | private int mSelectedPosition = NONE; |
| 207 | |
Anna Bauza | 1ad4dc5 | 2023-04-21 16:17:15 +0000 | [diff] [blame] | 208 | private int mLastSelectedPosition = NONE; |
| 209 | |
Oli Lan | f98ae93 | 2022-01-17 18:19:36 +0000 | [diff] [blame] | 210 | AvatarAdapter() { |
Oli Lan | b475112 | 2022-01-18 10:05:36 +0000 | [diff] [blame] | 211 | final boolean canTakePhoto = |
| 212 | PhotoCapabilityUtils.canTakePhoto(AvatarPickerActivity.this); |
| 213 | final boolean canChoosePhoto = |
| 214 | PhotoCapabilityUtils.canChoosePhoto(AvatarPickerActivity.this); |
| 215 | mTakePhotoPosition = (canTakePhoto ? 0 : NONE); |
| 216 | mChoosePhotoPosition = (canChoosePhoto ? (canTakePhoto ? 1 : 0) : NONE); |
| 217 | mPreselectedImageStartPosition = (canTakePhoto ? 1 : 0) + (canChoosePhoto ? 1 : 0); |
| 218 | |
Oli Lan | 4f3a0b8f | 2022-01-21 10:24:34 +0000 | [diff] [blame] | 219 | mPreselectedImages = getResources().obtainTypedArray(R.array.avatar_images); |
| 220 | mUserIconColors = UserIcons.getUserIconColors(getResources()); |
| 221 | mImageDrawables = buildDrawableList(); |
Oli Lan | 735747f | 2022-01-24 15:00:14 +0000 | [diff] [blame] | 222 | mImageDescriptions = buildDescriptionsList(); |
Oli Lan | f98ae93 | 2022-01-17 18:19:36 +0000 | [diff] [blame] | 223 | } |
| 224 | |
| 225 | @NonNull |
| 226 | @Override |
| 227 | public AvatarViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int position) { |
| 228 | LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext()); |
| 229 | View itemView = layoutInflater.inflate(R.layout.avatar_item, parent, false); |
| 230 | return new AvatarViewHolder(itemView); |
| 231 | } |
| 232 | |
| 233 | @Override |
| 234 | public void onBindViewHolder(@NonNull AvatarViewHolder viewHolder, int position) { |
Oli Lan | b475112 | 2022-01-18 10:05:36 +0000 | [diff] [blame] | 235 | if (position == mTakePhotoPosition) { |
| 236 | viewHolder.setDrawable(getDrawable(R.drawable.avatar_take_photo_circled)); |
Oli Lan | 735747f | 2022-01-24 15:00:14 +0000 | [diff] [blame] | 237 | viewHolder.setContentDescription(getString(R.string.user_image_take_photo)); |
Oli Lan | b475112 | 2022-01-18 10:05:36 +0000 | [diff] [blame] | 238 | |
| 239 | } else if (position == mChoosePhotoPosition) { |
| 240 | viewHolder.setDrawable(getDrawable(R.drawable.avatar_choose_photo_circled)); |
Oli Lan | 735747f | 2022-01-24 15:00:14 +0000 | [diff] [blame] | 241 | viewHolder.setContentDescription(getString(R.string.user_image_choose_photo)); |
Oli Lan | b475112 | 2022-01-18 10:05:36 +0000 | [diff] [blame] | 242 | |
| 243 | } else if (position >= mPreselectedImageStartPosition) { |
Oli Lan | 735747f | 2022-01-24 15:00:14 +0000 | [diff] [blame] | 244 | int index = indexFromPosition(position); |
Oli Lan | b475112 | 2022-01-18 10:05:36 +0000 | [diff] [blame] | 245 | viewHolder.setSelected(position == mSelectedPosition); |
Oli Lan | 735747f | 2022-01-24 15:00:14 +0000 | [diff] [blame] | 246 | viewHolder.setDrawable(mImageDrawables.get(index)); |
Oli Lan | f756b26 | 2023-06-14 11:26:32 +0100 | [diff] [blame] | 247 | if (mImageDescriptions != null && index < mImageDescriptions.size()) { |
Oli Lan | 735747f | 2022-01-24 15:00:14 +0000 | [diff] [blame] | 248 | viewHolder.setContentDescription(mImageDescriptions.get(index)); |
| 249 | } else { |
Anna Bauza | 1ad4dc5 | 2023-04-21 16:17:15 +0000 | [diff] [blame] | 250 | viewHolder.setContentDescription(getString( |
| 251 | R.string.default_user_icon_description)); |
Oli Lan | 735747f | 2022-01-24 15:00:14 +0000 | [diff] [blame] | 252 | } |
Oli Lan | b475112 | 2022-01-18 10:05:36 +0000 | [diff] [blame] | 253 | } |
Anna Bauza | 1ad4dc5 | 2023-04-21 16:17:15 +0000 | [diff] [blame] | 254 | viewHolder.setClickListener(view -> onViewHolderSelected(position)); |
| 255 | } |
| 256 | |
| 257 | private void onViewHolderSelected(int position) { |
| 258 | if ((mTakePhotoPosition == position) && (mLastSelectedPosition != position)) { |
| 259 | mAvatarPhotoController.takePhoto(); |
| 260 | } else if ((mChoosePhotoPosition == position) && (mLastSelectedPosition != position)) { |
| 261 | mAvatarPhotoController.choosePhoto(); |
| 262 | } else { |
| 263 | if (mSelectedPosition == position) { |
| 264 | deselect(position); |
| 265 | } else { |
| 266 | select(position); |
| 267 | } |
| 268 | } |
| 269 | mLastSelectedPosition = position; |
| 270 | } |
| 271 | |
| 272 | public void onAdapterResume() { |
| 273 | mLastSelectedPosition = NONE; |
Oli Lan | f98ae93 | 2022-01-17 18:19:36 +0000 | [diff] [blame] | 274 | } |
| 275 | |
| 276 | @Override |
| 277 | public int getItemCount() { |
Oli Lan | 4f3a0b8f | 2022-01-21 10:24:34 +0000 | [diff] [blame] | 278 | return mPreselectedImageStartPosition + mImageDrawables.size(); |
| 279 | } |
| 280 | |
| 281 | private List<Drawable> buildDrawableList() { |
| 282 | List<Drawable> result = new ArrayList<>(); |
| 283 | |
| 284 | for (int i = 0; i < mPreselectedImages.length(); i++) { |
| 285 | Drawable drawable = mPreselectedImages.getDrawable(i); |
| 286 | if (drawable instanceof BitmapDrawable) { |
| 287 | result.add(circularDrawableFrom((BitmapDrawable) drawable)); |
| 288 | } else { |
| 289 | throw new IllegalStateException("Avatar drawables must be bitmaps"); |
| 290 | } |
| 291 | } |
| 292 | if (!result.isEmpty()) { |
| 293 | return result; |
| 294 | } |
| 295 | |
| 296 | // No preselected images. Use tinted default icon. |
| 297 | for (int i = 0; i < mUserIconColors.length; i++) { |
| 298 | result.add(UserIcons.getDefaultUserIconInColor(getResources(), mUserIconColors[i])); |
| 299 | } |
| 300 | return result; |
Oli Lan | f98ae93 | 2022-01-17 18:19:36 +0000 | [diff] [blame] | 301 | } |
| 302 | |
Oli Lan | 735747f | 2022-01-24 15:00:14 +0000 | [diff] [blame] | 303 | private List<String> buildDescriptionsList() { |
| 304 | if (mPreselectedImages.length() > 0) { |
| 305 | return Arrays.asList( |
| 306 | getResources().getStringArray(R.array.avatar_image_descriptions)); |
| 307 | } |
| 308 | |
| 309 | return null; |
| 310 | } |
| 311 | |
Oli Lan | f98ae93 | 2022-01-17 18:19:36 +0000 | [diff] [blame] | 312 | private Drawable circularDrawableFrom(BitmapDrawable drawable) { |
| 313 | Bitmap bitmap = drawable.getBitmap(); |
| 314 | |
| 315 | RoundedBitmapDrawable roundedBitmapDrawable = |
| 316 | RoundedBitmapDrawableFactory.create(getResources(), bitmap); |
| 317 | roundedBitmapDrawable.setCircular(true); |
| 318 | |
| 319 | return roundedBitmapDrawable; |
| 320 | } |
| 321 | |
| 322 | private int indexFromPosition(int position) { |
Oli Lan | b475112 | 2022-01-18 10:05:36 +0000 | [diff] [blame] | 323 | return position - mPreselectedImageStartPosition; |
Oli Lan | f98ae93 | 2022-01-17 18:19:36 +0000 | [diff] [blame] | 324 | } |
| 325 | |
| 326 | private void select(int position) { |
| 327 | final int oldSelection = mSelectedPosition; |
| 328 | mSelectedPosition = position; |
| 329 | notifyItemChanged(position); |
| 330 | if (oldSelection != NONE) { |
| 331 | notifyItemChanged(oldSelection); |
| 332 | } else { |
| 333 | mDoneButton.setEnabled(true); |
| 334 | } |
| 335 | } |
| 336 | |
| 337 | private void deselect(int position) { |
| 338 | mSelectedPosition = NONE; |
| 339 | notifyItemChanged(position); |
| 340 | mDoneButton.setEnabled(false); |
| 341 | } |
Oli Lan | b475112 | 2022-01-18 10:05:36 +0000 | [diff] [blame] | 342 | |
Oli Lan | 4f3a0b8f | 2022-01-21 10:24:34 +0000 | [diff] [blame] | 343 | private void returnSelectionResult() { |
| 344 | int index = indexFromPosition(mSelectedPosition); |
| 345 | if (mPreselectedImages.length() > 0) { |
| 346 | int resourceId = mPreselectedImages.getResourceId(index, -1); |
| 347 | if (resourceId == -1) { |
| 348 | throw new IllegalStateException("Preselected avatar images must be resources."); |
| 349 | } |
| 350 | returnUriResult(uriForResourceId(resourceId)); |
| 351 | } else { |
| 352 | returnColorResult( |
| 353 | mUserIconColors[index]); |
Oli Lan | b475112 | 2022-01-18 10:05:36 +0000 | [diff] [blame] | 354 | } |
Oli Lan | b475112 | 2022-01-18 10:05:36 +0000 | [diff] [blame] | 355 | } |
| 356 | |
| 357 | private Uri uriForResourceId(int resourceId) { |
| 358 | return new Uri.Builder() |
| 359 | .scheme(ContentResolver.SCHEME_ANDROID_RESOURCE) |
| 360 | .authority(getResources().getResourcePackageName(resourceId)) |
| 361 | .appendPath(getResources().getResourceTypeName(resourceId)) |
| 362 | .appendPath(getResources().getResourceEntryName(resourceId)) |
| 363 | .build(); |
| 364 | } |
Oli Lan | f98ae93 | 2022-01-17 18:19:36 +0000 | [diff] [blame] | 365 | } |
| 366 | |
| 367 | private static class AvatarViewHolder extends RecyclerView.ViewHolder { |
| 368 | private final ImageView mImageView; |
| 369 | |
| 370 | AvatarViewHolder(View view) { |
| 371 | super(view); |
| 372 | mImageView = view.findViewById(R.id.avatar_image); |
| 373 | } |
| 374 | |
| 375 | public void setDrawable(Drawable drawable) { |
| 376 | mImageView.setImageDrawable(drawable); |
| 377 | } |
| 378 | |
Oli Lan | 735747f | 2022-01-24 15:00:14 +0000 | [diff] [blame] | 379 | public void setContentDescription(String desc) { |
| 380 | mImageView.setContentDescription(desc); |
| 381 | } |
| 382 | |
Oli Lan | f98ae93 | 2022-01-17 18:19:36 +0000 | [diff] [blame] | 383 | public void setClickListener(View.OnClickListener listener) { |
| 384 | mImageView.setOnClickListener(listener); |
| 385 | } |
| 386 | |
| 387 | public void setSelected(boolean selected) { |
| 388 | mImageView.setSelected(selected); |
| 389 | } |
| 390 | } |
| 391 | } |