[Android Apps and Games] Wuby986:
Imersive Preference class

Here we go, hold tight!!!

1st step:

create a new class in prefs subfolder and call it "ImmersivePreference" - without quotes of course.

how to: go left and click on project tab on the side margin and expand tree, in java/prefs folder right click and select new -> java class and put the name in

2nd step:

paste in the following code - no further explain on this i guess :D

package com.wubydax.romcontrol.prefs;

import android.app.AlertDialog;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.Bundle;
import android.preference.DialogPreference;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.Spinner;
import android.widget.TextView;

import com.wubydax.romcontrol.R;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;

/* Created by Roberto Mariani and Anna Berkovitch, 20/03/16
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.*/
public class ImmersivePreference extends DialogPreference {
Context c;
PackageManager pm;
String LOG_TAG ="list_log";
private List<AppInfo> mList;
private AsyncTask<Void, Void, Void> mAppLoader;
private RecyclerView recyclerView;
private List<String> mPersistedPackagesList;
private ProgressBar mProgressBar;
Spinner mSpinner;

public ImmersivePreference(Context context, AttributeSet attrs) {
super(context, attrs);
c = context;
pm = c.getPackageManager();
setDialogLayoutResource(R.layout.immersive_list);
}

private List<AppInfo> getAppList() {
List<AppInfo> list = new ArrayList<>();
Intent intent = new Intent(Intent.ACTION_MAIN, null);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
List<ResolveInfo> resolveInfos = pm.queryIntentActivities(intent, 0);
String persistedString = getPersistedString("");
Log.d(LOG_TAG, "getAppList persisted string is " + persistedString);
if (persistedString != null) {
String[] packagesArray = persistedString.split(";-");
Collections.addAll(mPersistedPackagesList, packagesArray);
}
for (int i = 0; i < resolveInfos.size(); i++) {
AppInfo appInfo = new AppInfo();
appInfo.appIcon = resolveInfos.get(i).activityInfo.loadIcon(pm);
appInfo.appLabel = resolveInfos.get(i).loadLabel(pm).toString();
appInfo.appPackage = resolveInfos.get(i).activityInfo.packageName;
appInfo.isSelected = mPersistedPackagesList.contains(appInfo.appPackage);
ActivityInfo ai = resolveInfos.get(i).activityInfo;

ComponentName name = new ComponentName(ai.applicationInfo.packageName,
ai.name);
Intent launchIntent = new Intent(Intent.ACTION_MAIN);
launchIntent.addCategory(Intent.CATEGORY_LAUNCHER);
launchIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
launchIntent.setComponent(name);
appInfo.intent = launchIntent;
list.add(appInfo);
}
return list;
}

public class AppInfo {
String appLabel;
String appPackage;
Drawable appIcon;
Intent intent;
boolean isSelected;
}

@Override
protected void showDialog(Bundle state) {
super.showDialog(state);
TypedValue typedValue = new TypedValue();
Resources.Theme theme = getContext().getTheme();
theme.resolveAttribute(R.attr.colorAccent, typedValue, true);
AlertDialog dialog = (AlertDialog) getDialog();
dialog.show();
Button cancel = dialog.getButton(AlertDialog.BUTTON_NEGATIVE);
Button ok = dialog.getButton(AlertDialog.BUTTON_POSITIVE);
cancel.setTextColor(typedValue.data);
ok.setTextColor(typedValue.data);
dialog.getWindow().setBackgroundDrawableResource(R.drawable.dialog_bg);
}

@Override
public void onClick(final DialogInterface dialog, int which) {
if (which == AlertDialog.BUTTON_POSITIVE) {
StringBuilder sb = new StringBuilder();
if (mSpinner.getSelectedItemPosition() != 0){
sb.append(getCurrentSpinnerValue());
Log.d(LOG_TAG, "onClick triggered by positive button");
for (String value : mPersistedPackagesList) {
if (!value.contains("immersive")){
Log.d(LOG_TAG, "onClick value is " + value);
if (!value.equals("")) {
sb.append(";-").append(value);
}
}
}} else {
sb.append(getCurrentSpinnerValue());
}
persistString(sb.toString());
Log.d(LOG_TAG, "onClick persisted string is " + sb.toString());
}
}

private String getCurrentSpinnerValue(){
String s ="";
int i = mSpinner.getSelectedItemPosition();
if (i == 0) {
s = "immersive.full";
} else if (i == 1) {
s = "immersive.full=*";
} else if(i == 2){
s = "immersive.navigation=*";
} else if(i == 3){
s = "immersive.status=*";
}

return s;
}

public int getSavedSpinnerValue() {
int i = 0;
String sub;
String value = getPersistedString("");
if (!Objects.equals(value, "")) {
if(value.contains("=")){
Log.d("spinner", "string value is " + value);
if (value.contains(";")){
sub = value.substring(0, value.indexOf(";"));
}else {
sub = value;
}

if (Objects.equals(sub, "immersive.full=*")) {

i = 1;
} else if (Objects.equals(sub, "immersive.navigation=*")) {
i = 2;
} else if (Objects.equals(sub, "immersive.status=*")) {
i = 3;
}
Log.d("spinner", "position value is " + i);
} else {
Log.d("spinner", "string value is " + value);
Log.d("spinner", "saved position is " + i);
i = 0;
}} return i;
}

@Override
protected void onBindDialogView(View view) {
super.onBindDialogView(view);
recyclerView = (RecyclerView) view.findViewById(R.id.recyclerView);
mPersistedPackagesList = new ArrayList<>();
mProgressBar = (ProgressBar) view.findViewById(R.id.progressBar2);
mSpinner = (Spinner) view.findViewById(R.id.spinner);
mSpinner.setSelection(getSavedSpinnerValue());
loadApps();
}

private void loadApps() {
mAppLoader = new AsyncTask<Void, Void, Void>() {

@Override
protected void onPreExecute() {
mProgressBar.setVisibility(View.VISIBLE);
}

@Override
protected Void doInBackground(Void... params) {
mList = getAppList();
Collections.sort(mList, new Comparator<AppInfo>() {

@Override
public int compare(AppInfo lhs, AppInfo rhs) {
return String.CASE_INSENSITIVE_ORDER.compare(lhs.appLabel, rhs.appLabel);
}
});
return null;
}

@Override
protected void onPostExecute(Void aVoid) {
mProgressBar.setVisibility(View.GONE);
LinearLayoutManager llm = new LinearLayoutManager(c);
recyclerView.setLayoutManager(llm);
AppAdapter appAdapter = new AppAdapter();
recyclerView.setAdapter(appAdapter);
}
}.execute();
}

public class AppAdapter extends RecyclerView.Adapter<AppAdapter.ViewHolder> {

@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_item, parent, false);
final ViewHolder vh = new ViewHolder(v);
v.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
vh.checkBox.setChecked(!vh.checkBox.isChecked());
}
});
return vh;
}

@Override
public void onBindViewHolder(ViewHolder holder, final int position) {
holder.appName.setText(mList.get(position).appLabel);
holder.appIcon.setImageDrawable(mList.get(position).appIcon);
holder.checkBox.setFocusable(false);
holder.checkBox.setOnCheckedChangeListener(null);
holder.checkBox.setChecked(mList.get(position).isSelected);
holder.checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
mPersistedPackagesList.add(mList.get(position).appPackage);
} else {
mPersistedPackagesList.remove(mList.get(position).appPackage);
}
mList.get(position).isSelected = isChecked;

}
});
}

@Override
public int getItemCount() {
if (mList != null) {
return mList.size();

} else {
return 0;
}
}

class ViewHolder extends RecyclerView.ViewHolder {
CheckBox checkBox;
ImageView appIcon;
TextView appName;

public ViewHolder(View itemView) {
super(itemView);
checkBox = (CheckBox) itemView.findViewById(R.id.checkBox);
appIcon = (ImageView) itemView.findViewById(R.id.appIcon);
appName = (TextView) itemView.findViewById(R.id.appName);
}
}
}

@Override
public void onDismiss(DialogInterface dialog) {
super.onDismiss(dialog);
if (mAppLoader != null && mAppLoader.getStatus() == AsyncTask.Status.RUNNING) {
mAppLoader.cancel(true);
mAppLoader = null;
}
}
}

3rd step: actually use it.. go in the uiprefs.xml in res/xml for example or anyway you want to insert it and add the line for it to show:

<com.wubydax.romcontrol.prefs.ImmersivePreference
android:title="immersive list"
android:key="policy_control" />

4th step:

we need to make the app handle the selection we make in the SharedPreferences, apply it in the settings.system DB and set the summary:

note i can already tell you there is the first time open bug that won't show the summary untill you make a change

go in the HandlePreferenceFragment

search for the onSharedPreferenceChange and at bottom of this method, right after the last break copy this code

case "ImmersivePreference":
ImmersivePreference ip = (ImmersivePreference) pf.findPreference(key);
String ipValue = sharedPreferences.getString(key, "");
if (Objects.equals(ipValue, "immersive.full") || Objects.equals(ipValue, "")) {
ip.setSummary("Off");
} else {
ip.setSummary("on - check selection");
}

actually here you should put the string ref: ip.setSummary(R.string.put_string_name); and create the string value so that you can translate if you want to

then still in the HandlePreferenceFragment search for the updateDatabase method -- you can search easily a class in studio by pressing " Ctrl + f " --

this method writes into the db, so since we need to add string we will add to the list of preference that are using Settings.System.putString(etc etc)...... so the line will look like

} else if (o instanceof MyEditTextPreference || o instanceof MyListPreference || o instanceof IntentDialogPreference || o instanceof ThumbnailListPreference || o instanceof ImmersivePreference) {
value = sp.getString(key, "");
Settings.System.putString(cr, key, value);

as you can see this line existes already, we just need to add the last " or " for it..

then next one is in the initAllKey method, right at bottom we add one more " or " to the Thumbnail if

which is going to look like

if(p instanceof ThumbnailListPreference || p instanceof ImmersivePreference) {
.......

last thing we need to add a couple of layouts:

so create two layouts named immersive_list and row_item

immersive_list will be like

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingEnd="16dp"
android:paddingStart="16dp">

<EditText
android:id="@+id/searchApp2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_marginTop="16dp"
android:backgroundTint="?attr/colorAccent"
android:backgroundTintMode="src_in"
android:hint="Find App"
android:visibility="gone" />

<Spinner
android:layout_width="match_parent"
android:layout_height="30dp"
android:entries="@array/immersive_spinner"
android:clickable="true"
android:id="@+id/spinner"
android:spinnerMode="dropdown"
android:layout_marginBottom="16dp"
android:layout_marginTop="16dp"
android:layout_below="@+id/searchApp2"
android:saveEnabled="true"/>

<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/recyclerView"
android:layout_below="@+id/spinner"/>

<ProgressBar
android:id="@+id/progressBar2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/spinner"
android:layout_centerHorizontal="true"
android:layout_marginBottom="16dp"
android:layout_marginTop="16dp"
android:indeterminate="true"
android:indeterminateTint="?attr/colorAccent"
android:indeterminateTintMode="src_in"
android:progressTint="?attr/colorAccent" />
</RelativeLayout>

while row_item will look like

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dp">

<CheckBox
android:id="@+id/checkBox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_centerVertical="true" />

<ImageView
android:id="@+id/appIcon"
android:layout_width="36dp"
android:layout_height="36dp"
android:layout_centerVertical="true"
android:layout_marginStart="10dp"
android:layout_toEndOf="@id/checkBox"
android:src="@mipmap/ic_launcher" />

<TextView
android:id="@+id/appName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginStart="10dp"
android:layout_toEndOf="@id/appIcon"
android:text="App Name"
android:textAppearance="?android:attr/textAppearanceMedium" />

</RelativeLayout>

i just hope i didn't forgot anything.. please let me know if i did :D

Edit!!!

forgot the array for the spinner!!!!! in rex/values/arrays.xml

<string-array name="immersive_spinner">
<item>Off</item>
<item>Full</item>
<item>Only NavBar</item>
<item>Only StatusBar</item>
</string-array>

IMPORTANT!!!!! if you want to change the order of the displayed option in the array above you'll need to change pretty much every ref to it around, since i based on selected position and not on the string, so you can translate strings no problem

of course big big thanks to [MENTION=4714483]daxgirl[/MENTION] for her usual help.. i would probably be bald already if it wasn't for her :D :D :D