diff --git a/res/color/option_border_color.xml b/res/color/option_border_color.xml new file mode 100644 index 0000000..880724c --- /dev/null +++ b/res/color/option_border_color.xml @@ -0,0 +1,25 @@ + + + + + + + diff --git a/res/drawable/icon_background.xml b/res/drawable/icon_background.xml new file mode 100644 index 0000000..e13ce6d --- /dev/null +++ b/res/drawable/icon_background.xml @@ -0,0 +1,19 @@ + + + + + + diff --git a/res/drawable/option_border_custom.xml b/res/drawable/option_border_custom.xml new file mode 100644 index 0000000..61f176e --- /dev/null +++ b/res/drawable/option_border_custom.xml @@ -0,0 +1,21 @@ + + + + + + + + + + diff --git a/res/drawable/option_border_edge_custom.xml b/res/drawable/option_border_edge_custom.xml new file mode 100644 index 0000000..197b445 --- /dev/null +++ b/res/drawable/option_border_edge_custom.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + diff --git a/res/layout/item_option.xml b/res/layout/item_option.xml new file mode 100644 index 0000000..fe137a0 --- /dev/null +++ b/res/layout/item_option.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + diff --git a/res/layout/item_view.xml b/res/layout/item_view.xml new file mode 100644 index 0000000..743d088 --- /dev/null +++ b/res/layout/item_view.xml @@ -0,0 +1,17 @@ + + + + + + + diff --git a/res/values/cherish_strings.xml b/res/values/cherish_strings.xml index 8632d96..224d346 100644 --- a/res/values/cherish_strings.xml +++ b/res/values/cherish_strings.xml @@ -687,5 +687,16 @@ Volume steps: System Volume steps: Voice Call Reset + + + Udfps + Udfps animation + Shows an animation while reading your finger + Udfps animation effect + Choose animation effect + + + Udfps icon picker + Choose your favorite fingerprint icon diff --git a/res/values/colors.xml b/res/values/colors.xml new file mode 100644 index 0000000..30aa424 --- /dev/null +++ b/res/values/colors.xml @@ -0,0 +1,24 @@ + + + + + + #5f6368 + @color/google_grey700 + @color/edit_background_base + + diff --git a/res/values/styles.xml b/res/values/styles.xml new file mode 100644 index 0000000..59a404e --- /dev/null +++ b/res/values/styles.xml @@ -0,0 +1,21 @@ + + + + + + diff --git a/res/xml/cherish_settings_lockscreen.xml b/res/xml/cherish_settings_lockscreen.xml index a4de6af..e51d1dd 100644 --- a/res/xml/cherish_settings_lockscreen.xml +++ b/res/xml/cherish_settings_lockscreen.xml @@ -91,6 +91,10 @@ + + + + + + + + diff --git a/src/com/cherish/settings/fragments/LockScreenSettings.java b/src/com/cherish/settings/fragments/LockScreenSettings.java index f1a353a..4d024db 100644 --- a/src/com/cherish/settings/fragments/LockScreenSettings.java +++ b/src/com/cherish/settings/fragments/LockScreenSettings.java @@ -51,6 +51,7 @@ import com.android.settings.search.BaseSearchIndexProvider; import com.android.settingslib.search.SearchIndexable; import android.provider.SearchIndexableResource; import com.android.internal.util.cherish.fod.FodUtils; +import com.android.internal.util.cherish.CherishUtils; import java.util.ArrayList; import java.util.List; @@ -92,11 +93,11 @@ public class LockScreenSettings extends SettingsPreferenceFragment implements e.printStackTrace(); } + PreferenceCategory udfps = (PreferenceCategory) prefScreen.findPreference("udfps_category"); mFODScreenOff = (SystemSettingSwitchPreference) findPreference(SCREEN_OFF_FOD_KEY); mUdfpsHapticFeedback = (SystemSettingSwitchPreference) findPreference(UDFPS_HAPTIC_FEEDBACK); if (!FodUtils.hasFodSupport(getContext())) { - prefScreen.removePreference(mFODScreenOff); - prefScreen.removePreference(mUdfpsHapticFeedback); + prefScreen.removePreference(udfps); } mAODPref = findPreference(AOD_SCHEDULE_KEY); diff --git a/src/com/cherish/settings/fragments/UdfpsAnimation.java b/src/com/cherish/settings/fragments/UdfpsAnimation.java new file mode 100644 index 0000000..5d22bcb --- /dev/null +++ b/src/com/cherish/settings/fragments/UdfpsAnimation.java @@ -0,0 +1,264 @@ +/* + * Copyright (C) 2021 AospExtended ROM 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.cherish.settings.fragments; + +import android.content.ContentResolver; +import android.content.Context; +import android.content.res.Resources; +import android.content.pm.PackageManager; +import android.graphics.drawable.AnimationDrawable; +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.provider.SearchIndexableResource; +import android.provider.Settings; +import android.view.LayoutInflater; +import android.view.View; +import android.view.Gravity; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.FrameLayout; +import android.widget.TextView; +import android.widget.Toast; +import android.text.TextUtils; +import androidx.preference.PreferenceViewHolder; +import android.view.ViewGroup.LayoutParams; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.GridLayoutManager; +import androidx.recyclerview.widget.RecyclerView.ViewHolder; +import androidx.recyclerview.widget.RecyclerView; +import android.net.Uri; +import androidx.core.content.res.ResourcesCompat; +import androidx.preference.Preference; +import androidx.preference.Preference.OnPreferenceChangeListener; +import androidx.preference.PreferenceScreen; + +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; +import com.android.settings.R; +import com.android.settings.search.BaseSearchIndexProvider; +import com.android.settingslib.search.Indexable; +import com.android.settings.SettingsPreferenceFragment; + +import android.widget.Switch; +import com.android.settings.SettingsActivity; +import com.android.settings.widget.SettingsMainSwitchBar; +import com.android.settingslib.widget.OnMainSwitchChangeListener; + +import com.bumptech.glide.Glide; + +import java.util.ArrayList; +import java.util.List; +import java.util.Arrays; + +import org.json.JSONObject; +import org.json.JSONException; + +public class UdfpsAnimation extends SettingsPreferenceFragment implements + OnMainSwitchChangeListener { + + private Switch mSwitch; + + private RecyclerView mRecyclerView; + private String mPkg = "com.cherish.udfps.resources"; + private AnimationDrawable animation; + + private Resources udfpsRes; + + private String[] mAnims; + private String[] mAnimPreviews; + private String[] mTitles; + + private boolean mEnabled; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + getActivity().setTitle(R.string.udfps_recog_animation_effect_title); + + loadResources(); + } + + private void loadResources() { + try { + PackageManager pm = getActivity().getPackageManager(); + udfpsRes = pm.getResourcesForApplication(mPkg); + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + } + + mAnims = udfpsRes.getStringArray(udfpsRes.getIdentifier("udfps_animation_styles", + "array", mPkg)); + mAnimPreviews = udfpsRes.getStringArray(udfpsRes.getIdentifier("udfps_animation_previews", + "array", mPkg)); + mTitles = udfpsRes.getStringArray(udfpsRes.getIdentifier("udfps_animation_titles", + "array", mPkg)); + } + + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + View view = inflater.inflate( + R.layout.item_view, container, false); + + mRecyclerView = (RecyclerView) view.findViewById(R.id.recycler_view); + GridLayoutManager gridLayoutManager = new GridLayoutManager(getActivity(), 3); + mRecyclerView.setLayoutManager(gridLayoutManager); + UdfpsAnimAdapter mUdfpsAnimAdapter = new UdfpsAnimAdapter(getActivity()); + mRecyclerView.setAdapter(mUdfpsAnimAdapter); + + return view; + } + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + final SettingsActivity activity = (SettingsActivity) getActivity(); + final SettingsMainSwitchBar switchBar = activity.getSwitchBar(); + mSwitch = switchBar.getSwitch(); + mEnabled = Settings.System.getInt(getActivity().getContentResolver(), + Settings.System.UDFPS_ANIM, 0) == 1; + mSwitch.setChecked(mEnabled); + setEnabled(mEnabled); + switchBar.setTitle(getActivity().getString(R.string.udfps_recog_animation)); + switchBar.addOnSwitchChangeListener(this); + switchBar.show(); + } + + @Override + public void onSwitchChanged(Switch switchView, boolean isChecked) { + Settings.System.putInt(getActivity().getContentResolver(), + Settings.System.UDFPS_ANIM, isChecked ? 1 : 0); + setEnabled(isChecked); + } + + public void setEnabled(boolean enabled) { + for (int i = 0; i < mRecyclerView.getChildCount(); ++i) { + RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(mRecyclerView.getChildAt(i)); + holder.itemView.setEnabled(enabled); + holder.itemView.findViewById(R.id.option_thumbnail).setAlpha(enabled ? 1f : 0.5f); + holder.itemView.findViewById(R.id.option_label).setAlpha(enabled ? 1f : 0.5f); + } + } + + @Override + public int getMetricsCategory() { + return MetricsEvent.CHERISH_SETTINGS; + } + + @Override + public void onResume() { + super.onResume(); + } + + public class UdfpsAnimAdapter extends RecyclerView.Adapter { + Context context; + String mSelectedAnim; + String mAppliedAnim; + + public UdfpsAnimAdapter(Context context) { + this.context = context; + } + + @Override + public UdfpsAnimViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_option, parent, false); + UdfpsAnimViewHolder vh = new UdfpsAnimViewHolder(v); + return vh; + } + + @Override + public void onBindViewHolder(UdfpsAnimViewHolder holder, final int position) { + String animName = mAnims[position]; + + Glide.with(holder.image.getContext()) + .load("") + .placeholder(getDrawable(holder.image.getContext(), mAnimPreviews[position])) + .into(holder.image); + + holder.name.setText(mTitles[position]); + + if (position == Settings.System.getInt(context.getContentResolver(), + Settings.System.UDFPS_ANIM_STYLE, 0)) { + mAppliedAnim = animName; + if (mSelectedAnim == null) { + mSelectedAnim = animName; + } + } + + holder.itemView.setActivated(animName == mSelectedAnim); + holder.itemView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + updateActivatedStatus(mSelectedAnim, false); + updateActivatedStatus(animName, true); + mSelectedAnim = animName; + holder.image.setBackgroundDrawable(getDrawable(v.getContext(), mAnims[position])); + animation = (AnimationDrawable) holder.image.getBackground(); + animation.setOneShot(true); + animation.start(); + Settings.System.putInt(getActivity().getContentResolver(), + Settings.System.UDFPS_ANIM_STYLE, position); + } + }); + + holder.itemView.setEnabled(mEnabled); + holder.itemView.findViewById(R.id.option_thumbnail).setAlpha(mEnabled ? 1f : 0.5f); + holder.itemView.findViewById(R.id.option_label).setAlpha(mEnabled ? 1f : 0.5f); + } + + @Override + public int getItemCount() { + return mAnims.length; + } + + public class UdfpsAnimViewHolder extends RecyclerView.ViewHolder { + TextView name; + ImageView image; + public UdfpsAnimViewHolder(View itemView) { + super(itemView); + name = (TextView) itemView.findViewById(R.id.option_label); + image = (ImageView) itemView.findViewById(R.id.option_thumbnail); + } + } + + private void updateActivatedStatus(String anim, boolean isActivated) { + int index = Arrays.asList(mAnims).indexOf(anim); + if (index < 0) { + return; + } + RecyclerView.ViewHolder holder = mRecyclerView.findViewHolderForAdapterPosition(index); + if (holder != null && holder.itemView != null) { + holder.itemView.setActivated(isActivated); + } + } + } + + public Drawable getDrawable(Context context, String drawableName) { + try { + PackageManager pm = context.getPackageManager(); + Resources res = pm.getResourcesForApplication(mPkg); + return res.getDrawable(res.getIdentifier(drawableName, "drawable", mPkg)); + } + catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + } + return null; + } + +} diff --git a/src/com/cherish/settings/fragments/UdfpsIconPicker.java b/src/com/cherish/settings/fragments/UdfpsIconPicker.java new file mode 100644 index 0000000..b155a61 --- /dev/null +++ b/src/com/cherish/settings/fragments/UdfpsIconPicker.java @@ -0,0 +1,211 @@ +/* + * Copyright (C) 2021 AospExtended ROM 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.cherish.settings.fragments; + +import android.content.ContentResolver; +import android.content.Context; +import android.content.res.Resources; +import android.content.pm.PackageManager; +import android.graphics.drawable.AnimationDrawable; +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.provider.SearchIndexableResource; +import android.provider.Settings; +import android.view.LayoutInflater; +import android.view.View; +import android.view.Gravity; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.FrameLayout; +import android.widget.TextView; +import android.widget.Toast; +import android.text.TextUtils; +import androidx.preference.PreferenceViewHolder; +import android.view.ViewGroup.LayoutParams; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.GridLayoutManager; +import androidx.recyclerview.widget.RecyclerView.ViewHolder; +import androidx.recyclerview.widget.RecyclerView; +import android.net.Uri; +import androidx.core.content.res.ResourcesCompat; +import androidx.preference.Preference; +import androidx.preference.Preference.OnPreferenceChangeListener; +import androidx.preference.PreferenceScreen; + +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; +import com.android.settings.R; +import com.android.settings.search.BaseSearchIndexProvider; +import com.android.settingslib.search.Indexable; +import com.android.settings.SettingsPreferenceFragment; + +import com.bumptech.glide.Glide; + +import java.util.ArrayList; +import java.util.List; +import java.util.Arrays; + +import org.json.JSONObject; +import org.json.JSONException; + +public class UdfpsIconPicker extends SettingsPreferenceFragment { + + private RecyclerView mRecyclerView; + + private Resources udfpsRes; + + private String mPkg = "com.cherish.udfps.resources"; + + private String[] mIcons; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + getActivity().setTitle(R.string.udfps_icon_picker_title); + + loadResources(); + } + + private void loadResources() { + try { + PackageManager pm = getActivity().getPackageManager(); + udfpsRes = pm.getResourcesForApplication(mPkg); + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + } + + mIcons = udfpsRes.getStringArray(udfpsRes.getIdentifier("udfps_icons", + "array", mPkg)); + } + + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + View view = inflater.inflate( + R.layout.item_view, container, false); + + mRecyclerView = (RecyclerView) view.findViewById(R.id.recycler_view); + GridLayoutManager gridLayoutManager = new GridLayoutManager(getActivity(), 3); + mRecyclerView.setLayoutManager(gridLayoutManager); + UdfpsIconAdapter mUdfpsIconAdapter = new UdfpsIconAdapter(getActivity()); + mRecyclerView.setAdapter(mUdfpsIconAdapter); + + return view; + } + + @Override + public int getMetricsCategory() { + return MetricsEvent.CHERISH_SETTINGS; + } + + @Override + public void onResume() { + super.onResume(); + } + + public class UdfpsIconAdapter extends RecyclerView.Adapter { + Context context; + String mSelectedIcon; + String mAppliedIcon; + + public UdfpsIconAdapter(Context context) { + this.context = context; + } + + @Override + public UdfpsIconViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_option, parent, false); + UdfpsIconViewHolder vh = new UdfpsIconViewHolder(v); + return vh; + } + + @Override + public void onBindViewHolder(UdfpsIconViewHolder holder, final int position) { + String iconRes = mIcons[position]; + + Glide.with(holder.image.getContext()) + .load("") + .placeholder(getDrawable(holder.image.getContext(), mIcons[position])) + .into(holder.image); + + holder.image.setPadding(20,20,20,20); + + holder.name.setVisibility(View.GONE); + + if (position == Settings.System.getInt(context.getContentResolver(), + Settings.System.UDFPS_ICON, 0)) { + mAppliedIcon = iconRes; + if (mSelectedIcon == null) { + mSelectedIcon = iconRes; + } + } + holder.itemView.setActivated(iconRes == mSelectedIcon); + holder.itemView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + updateActivatedStatus(mSelectedIcon, false); + updateActivatedStatus(iconRes, true); + mSelectedIcon = iconRes; + Settings.System.putInt(getActivity().getContentResolver(), + Settings.System.UDFPS_ICON, position); + } + }); + } + + @Override + public int getItemCount() { + return mIcons.length; + } + + public class UdfpsIconViewHolder extends RecyclerView.ViewHolder { + TextView name; + ImageView image; + public UdfpsIconViewHolder(View itemView) { + super(itemView); + name = (TextView) itemView.findViewById(R.id.option_label); + image = (ImageView) itemView.findViewById(R.id.option_thumbnail); + } + } + + private void updateActivatedStatus(String icon, boolean isActivated) { + int index = Arrays.asList(mIcons).indexOf(icon); + if (index < 0) { + return; + } + RecyclerView.ViewHolder holder = mRecyclerView.findViewHolderForAdapterPosition(index); + if (holder != null && holder.itemView != null) { + holder.itemView.setActivated(isActivated); + } + } + } + + public Drawable getDrawable(Context context, String drawableName) { + try { + PackageManager pm = context.getPackageManager(); + Resources res = pm.getResourcesForApplication(mPkg); + Context ctx = context.createPackageContext( + mPkg, Context.CONTEXT_IGNORE_SECURITY); + return ctx.getDrawable(res.getIdentifier(drawableName, "drawable", mPkg)); + } + catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + } + return null; + } +}