/* * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.settingslib.users; import android.app.Activity; import android.content.ContentResolver; import android.content.Intent; import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import androidx.annotation.NonNull; import androidx.core.graphics.drawable.RoundedBitmapDrawable; import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory; import androidx.recyclerview.widget.GridLayoutManager; import androidx.recyclerview.widget.RecyclerView; import com.android.internal.util.UserIcons; import com.android.settingslib.R; import com.google.android.setupcompat.template.FooterBarMixin; import com.google.android.setupcompat.template.FooterButton; import com.google.android.setupdesign.GlifLayout; import com.google.android.setupdesign.util.ThemeHelper; import com.google.android.setupdesign.util.ThemeResolver; import java.util.ArrayList; import java.util.Arrays; import java.util.List; /** * Activity to allow the user to choose a user profile picture. * *
Options are provided to take a photo or choose a photo using the photo picker. In addition, * preselected avatar images may be provided in the resource array {@code avatar_images}. If * provided, every element of that array must be a bitmap drawable. * *
If preselected images are not provided, the default avatar will be shown instead, in a range * of colors. * *
This activity should be started with startActivityForResult. If a photo or a preselected image
* is selected, a Uri will be returned in the data field of the result intent. If a colored default
* avatar is selected, the chosen color will be returned as {@code EXTRA_DEFAULT_ICON_TINT_COLOR}
* and the data field will be empty.
*/
public class AvatarPickerActivity extends Activity {
static final String EXTRA_FILE_AUTHORITY = "file_authority";
static final String EXTRA_DEFAULT_ICON_TINT_COLOR = "default_icon_tint_color";
private static final String KEY_AWAITING_RESULT = "awaiting_result";
private static final String KEY_SELECTED_POSITION = "selected_position";
private boolean mWaitingForActivityResult;
private FooterButton mDoneButton;
private AvatarAdapter mAdapter;
private AvatarPhotoController mAvatarPhotoController;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
boolean dayNightEnabled = ThemeHelper.isSetupWizardDayNightEnabled(this);
ThemeResolver themeResolver =
new ThemeResolver.Builder(ThemeResolver.getDefault())
.setDefaultTheme(ThemeHelper.getSuwDefaultTheme(this))
.setUseDayNight(true)
.build();
int themeResId = themeResolver.resolve("", /* suppressDayNight= */ !dayNightEnabled);
setTheme(themeResId);
ThemeHelper.trySetDynamicColor(this);
setContentView(R.layout.avatar_picker);
setUpButtons();
RecyclerView recyclerView = findViewById(R.id.avatar_grid);
mAdapter = new AvatarAdapter();
recyclerView.setAdapter(mAdapter);
recyclerView.setLayoutManager(new GridLayoutManager(this,
getResources().getInteger(R.integer.avatar_picker_columns)));
restoreState(savedInstanceState);
mAvatarPhotoController = new AvatarPhotoController(
new AvatarPhotoController.AvatarUiImpl(this),
new AvatarPhotoController.ContextInjectorImpl(this, getFileAuthority()),
mWaitingForActivityResult);
}
@Override
protected void onResume() {
super.onResume();
mAdapter.onAdapterResume();
}
private void setUpButtons() {
GlifLayout glifLayout = findViewById(R.id.glif_layout);
FooterBarMixin mixin = glifLayout.getMixin(FooterBarMixin.class);
FooterButton secondaryButton =
new FooterButton.Builder(this)
.setText(getString(android.R.string.cancel))
.setListener(view -> cancel())
.build();
mDoneButton =
new FooterButton.Builder(this)
.setText(getString(R.string.done))
.setListener(view -> mAdapter.returnSelectionResult())
.build();
mDoneButton.setEnabled(false);
mixin.setSecondaryButton(secondaryButton);
mixin.setPrimaryButton(mDoneButton);
}
private String getFileAuthority() {
String authority = getIntent().getStringExtra(EXTRA_FILE_AUTHORITY);
if (authority == null) {
throw new IllegalStateException("File authority must be provided");
}
return authority;
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
mWaitingForActivityResult = false;
mAvatarPhotoController.onActivityResult(requestCode, resultCode, data);
}
@Override
protected void onSaveInstanceState(@NonNull Bundle outState) {
outState.putBoolean(KEY_AWAITING_RESULT, mWaitingForActivityResult);
outState.putInt(KEY_SELECTED_POSITION, mAdapter.mSelectedPosition);
super.onSaveInstanceState(outState);
}
private void restoreState(Bundle savedInstanceState) {
if (savedInstanceState != null) {
mWaitingForActivityResult = savedInstanceState.getBoolean(KEY_AWAITING_RESULT, false);
mAdapter.mSelectedPosition =
savedInstanceState.getInt(KEY_SELECTED_POSITION, AvatarAdapter.NONE);
mDoneButton.setEnabled(mAdapter.mSelectedPosition != AvatarAdapter.NONE);
}
}
@Override
public void startActivityForResult(Intent intent, int requestCode) {
mWaitingForActivityResult = true;
super.startActivityForResult(intent, requestCode);
}
void returnUriResult(Uri uri) {
Intent resultData = new Intent();
resultData.setData(uri);
setResult(RESULT_OK, resultData);
finish();
}
void returnColorResult(int color) {
Intent resultData = new Intent();
resultData.putExtra(EXTRA_DEFAULT_ICON_TINT_COLOR, color);
setResult(RESULT_OK, resultData);
finish();
}
private void cancel() {
setResult(RESULT_CANCELED);
finish();
}
private class AvatarAdapter extends RecyclerView.Adapter