Use flavors for mapbox vs vtm

This commit is contained in:
Marvin W 2020-07-09 09:53:37 +02:00
commit 8eff51cfb6
No known key found for this signature in database
GPG key ID: 072E9235DB996F2A
63 changed files with 40 additions and 28 deletions

View file

@ -16,17 +16,12 @@
apply plugin: 'com.android.application'
def useMapbox() {
Properties properties = new Properties()
properties.load(project.rootProject.file('local.properties').newDataInputStream())
return properties.getProperty("mapbox.enabled", "false") == "true"
configurations {
mapboxImplementation
vtmImplementation
}
dependencies {
implementation "androidx.multidex:multidex:$multidexVersion"
implementation "androidx.appcompat:appcompat:$appcompatVersion"
implementation "androidx.mediarouter:mediarouter:$mediarouterVersion"
implementation "androidx.preference:preference:$preferenceVersion"
implementation "com.squareup.wire:wire-runtime:1.6.1"
implementation "de.hdodenhof:circleimageview:1.3.0"
implementation "org.conscrypt:conscrypt-android:2.1.0"
@ -42,18 +37,21 @@ dependencies {
implementation project(':play-services-base-core')
implementation project(':play-services-location-core')
implementation project(':microg-ui-tools')
implementation project(':play-services-core:microg-ui-tools') // deprecated
implementation project(':play-services-api')
implementation project(':play-services-cast-api')
implementation project(':play-services-wearable')
implementation "org.microg:wearable:$wearableVersion"
implementation "org.microg.gms:remote-droid-guard:$remoteDroidGuardVersion"
if (useMapbox()) {
implementation project(':play-services-maps-core-mapbox')
} else {
implementation project(':play-services-maps-core-vtm')
}
mapboxImplementation project(':play-services-maps-core-mapbox')
vtmImplementation project(':play-services-maps-core-vtm')
// AndroidX UI
implementation "androidx.multidex:multidex:$multidexVersion"
implementation "androidx.appcompat:appcompat:$appcompatVersion"
implementation "androidx.mediarouter:mediarouter:$mediarouterVersion"
implementation "androidx.preference:preference:$preferenceVersion"
// Navigation
implementation "androidx.navigation:navigation-fragment:$navigationVersion"
@ -67,13 +65,13 @@ android {
buildToolsVersion "$androidBuildVersionTools"
defaultConfig {
versionName version + (useMapbox() ? "" : "-vtm")
versionName version
versionCode appVersionCode
minSdkVersion androidMinSdk
targetSdkVersion androidTargetSdk
buildConfigField "boolean", "USE_MAPBOX", "${useMapbox()}"
// buildConfigField "boolean", "USE_MAPBOX", "${useMapbox()}"
multiDexEnabled true
@ -103,6 +101,17 @@ android {
}
}
flavorDimensions 'maps'
productFlavors {
mapbox {
dimension 'maps'
}
vtm {
dimension 'maps'
versionNameSuffix '-vtm'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8

View file

@ -0,0 +1,44 @@
/*
* Copyright 2013-2016 microG Project Team
*
* 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.
*/
apply plugin: 'com.android.library'
android {
compileSdkVersion androidCompileSdk
buildToolsVersion "$androidBuildVersionTools"
defaultConfig {
versionName version
minSdkVersion androidMinSdk
targetSdkVersion androidTargetSdk
}
compileOptions {
sourceCompatibility = 1.8
targetCompatibility = 1.8
}
lintOptions {
// TODO: Remove MissingTranslation once we have stable strings and proper translations.
disable 'MissingTranslation'
}
}
dependencies {
implementation "androidx.appcompat:appcompat:$appcompatVersion"
implementation "androidx.preference:preference:$preferenceVersion"
}

View file

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2013-2017 microG Project Team
~
~ 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.
-->
<manifest package="org.microg.tools.ui" />

View file

@ -0,0 +1,77 @@
/*
* Copyright (C) 2013-2017 microG Project Team
*
* 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 org.microg.tools.selfcheck;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.PermissionGroupInfo;
import android.content.pm.PermissionInfo;
import android.util.Log;
import androidx.fragment.app.Fragment;
import org.microg.tools.ui.R;
import static android.os.Build.VERSION_CODES.M;
import static org.microg.tools.selfcheck.SelfCheckGroup.Result.Negative;
import static org.microg.tools.selfcheck.SelfCheckGroup.Result.Positive;
@TargetApi(M)
public class PermissionCheckGroup implements SelfCheckGroup {
private static final String TAG = "SelfCheckPerms";
private String[] permissions;
public PermissionCheckGroup(String... permissions) {
this.permissions = permissions;
}
@Override
public String getGroupName(Context context) {
return context.getString(R.string.self_check_cat_permissions);
}
@Override
public void doChecks(Context context, ResultCollector collector) {
for (String permission : permissions) {
doPermissionCheck(context, collector, permission);
}
}
private void doPermissionCheck(Context context, ResultCollector collector, final String permission) {
PackageManager pm = context.getPackageManager();
try {
PermissionInfo info = pm.getPermissionInfo(permission, 0);
PermissionGroupInfo groupInfo = info.group != null ? pm.getPermissionGroupInfo(info.group, 0) : null;
CharSequence permLabel = info.loadLabel(pm);
CharSequence groupLabel = groupInfo != null ? groupInfo.loadLabel(pm) : permLabel;
collector.addResult(context.getString(R.string.self_check_name_permission, permLabel),
context.checkSelfPermission(permission) == PackageManager.PERMISSION_GRANTED ? Positive : Negative,
context.getString(R.string.self_check_resolution_permission, groupLabel),
new SelfCheckGroup.CheckResolver() {
@Override
public void tryResolve(Fragment fragment) {
fragment.requestPermissions(new String[]{permission}, 0);
}
});
} catch (PackageManager.NameNotFoundException e) {
Log.w(TAG, e);
}
}
}

View file

@ -0,0 +1,41 @@
/*
* Copyright (C) 2013-2017 microG Project Team
*
* 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 org.microg.tools.selfcheck;
import android.content.Context;
import androidx.fragment.app.Fragment;
public interface SelfCheckGroup {
String getGroupName(Context context);
void doChecks(Context context, ResultCollector collector);
interface ResultCollector {
void addResult(String name, Result value, String resolution);
void addResult(String name, Result value, String resolution, CheckResolver resolver);
}
interface CheckResolver {
void tryResolve(Fragment fragment);
}
enum Result {
Positive, Negative, Unknown
}
}

View file

@ -0,0 +1,149 @@
/*
* Copyright (C) 2013-2017 microG Project Team
*
* 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 org.microg.tools.ui;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
public abstract class AbstractAboutFragment extends Fragment {
protected abstract void collectLibraries(List<Library> libraries);
public static Drawable getIcon(Context context) {
try {
PackageManager pm = context.getPackageManager();
return pm.getPackageInfo(context.getPackageName(), 0).applicationInfo.loadIcon(pm);
} catch (PackageManager.NameNotFoundException e) {
// Never happens, self package always exists!
throw new RuntimeException(e);
}
}
public static String getAppName(Context context) {
try {
PackageManager pm = context.getPackageManager();
CharSequence label = pm.getPackageInfo(context.getPackageName(), 0).applicationInfo.loadLabel(pm);
if (TextUtils.isEmpty(label)) return context.getPackageName();
return label.toString().trim();
} catch (PackageManager.NameNotFoundException e) {
// Never happens, self package always exists!
throw new RuntimeException(e);
}
}
protected String getAppName() {
return getAppName(getContext());
}
public static String getLibVersion(String packageName) {
try {
String versionName = (String) Class.forName(packageName + ".BuildConfig").getField("VERSION_NAME").get(null);
if (TextUtils.isEmpty(versionName)) return "";
return versionName.trim();
} catch (Exception e) {
return "";
}
}
public static String getSelfVersion(Context context) {
return getLibVersion(context.getPackageName());
}
protected String getSelfVersion() {
return getSelfVersion(getContext());
}
protected String getSummary() {
return null;
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View aboutRoot = inflater.inflate(R.layout.about_root, container, false);
((ImageView) aboutRoot.findViewById(android.R.id.icon)).setImageDrawable(getIcon(getContext()));
((TextView) aboutRoot.findViewById(android.R.id.title)).setText(getAppName());
((TextView) aboutRoot.findViewById(R.id.about_version)).setText(getString(R.string.about_version_str, getSelfVersion()));
String summary = getSummary();
if (summary != null) {
((TextView) aboutRoot.findViewById(android.R.id.summary)).setText(summary);
aboutRoot.findViewById(android.R.id.summary).setVisibility(View.VISIBLE);
}
List<Library> libraries = new ArrayList<Library>();
collectLibraries(libraries);
Collections.sort(libraries);
((ListView) aboutRoot.findViewById(android.R.id.list)).setAdapter(new LibraryAdapter(getContext(), libraries.toArray(new Library[libraries.size()])));
return aboutRoot;
}
private class LibraryAdapter extends ArrayAdapter<Library> {
public LibraryAdapter(Context context, Library[] libraries) {
super(context, android.R.layout.simple_list_item_2, android.R.id.text1, libraries);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = super.getView(position, convertView, parent);
((TextView) v.findViewById(android.R.id.text1)).setText(getString(R.string.about_name_version_str, getItem(position).name, getLibVersion(getItem(position).packageName)));
((TextView) v.findViewById(android.R.id.text2)).setText(getItem(position).copyright != null ? getItem(position).copyright : getString(R.string.about_default_license));
return v;
}
}
protected static class Library implements Comparable<Library> {
private final String packageName;
private final String name;
private final String copyright;
public Library(String packageName, String name, String copyright) {
this.packageName = packageName;
this.name = name;
this.copyright = copyright;
}
@Override
public String toString() {
return name + ", " + copyright;
}
@Override
public int compareTo(Library another) {
return name.toLowerCase(Locale.US).compareTo(another.name.toLowerCase(Locale.US));
}
}
}

View file

@ -0,0 +1,113 @@
package org.microg.tools.ui;
import android.os.Bundle;
import android.view.ViewGroup;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import java.util.ArrayList;
import java.util.List;
public abstract class AbstractDashboardActivity extends AppCompatActivity {
protected int preferencesResource = 0;
private final List<Condition> conditions = new ArrayList<Condition>();
private ViewGroup conditionContainer;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.dashboard_activity);
conditionContainer = (ViewGroup) findViewById(R.id.condition_container);
getSupportFragmentManager().beginTransaction()
.replace(R.id.content_wrapper, getFragment())
.commit();
}
@Override
protected void onResume() {
super.onResume();
forceConditionReevaluation();
}
private synchronized void resetConditionViews() {
conditionContainer.removeAllViews();
for (Condition condition : conditions) {
if (condition.isEvaluated()) {
if (condition.isActive(this)) {
addConditionToView(condition);
}
} else {
evaluateConditionAsync(condition);
}
}
}
private void evaluateConditionAsync(final Condition condition) {
if (condition.willBeEvaluating()) {
new Thread(new Runnable() {
@Override
public void run() {
if (condition.isActive(AbstractDashboardActivity.this)) {
runOnUiThread(new Runnable() {
@Override
public void run() {
if (conditions.contains(condition) && condition.isEvaluated()) {
addConditionToView(condition);
}
}
});
}
}
}).start();
}
}
protected void forceConditionReevaluation() {
for (Condition condition : conditions) {
condition.resetEvaluated();
}
resetConditionViews();
}
protected void addAllConditions(Condition[] conditions) {
for (Condition condition : conditions) {
addCondition(condition);
}
}
protected void addCondition(Condition condition) {
conditions.add(condition);
if (conditionContainer == null) return;
if (condition.isEvaluated()) {
addConditionToView(condition);
} else {
evaluateConditionAsync(condition);
}
}
private synchronized void addConditionToView(Condition condition) {
for (int i = 0; i < conditionContainer.getChildCount(); i++) {
if (conditionContainer.getChildAt(i).getTag() == condition) return;
}
conditionContainer.addView(condition.createView(this, conditionContainer));
}
protected void clearConditions() {
conditions.clear();
resetConditionViews();
}
protected Fragment getFragment() {
if (preferencesResource == 0) {
throw new IllegalStateException("Neither preferencesResource given, nor overriden getFragment()");
}
ResourceSettingsFragment fragment = new ResourceSettingsFragment();
Bundle b = new Bundle();
b.putInt(ResourceSettingsFragment.EXTRA_PREFERENCE_RESOURCE, preferencesResource);
fragment.setArguments(b);
return fragment;
}
}

View file

@ -0,0 +1,128 @@
/*
* Copyright (C) 2013-2017 microG Project Team
*
* 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 org.microg.tools.ui;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.TextView;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import org.microg.tools.selfcheck.SelfCheckGroup;
import java.util.ArrayList;
import java.util.List;
import static android.view.View.GONE;
import static android.view.View.INVISIBLE;
import static org.microg.tools.selfcheck.SelfCheckGroup.Result.Negative;
import static org.microg.tools.selfcheck.SelfCheckGroup.Result.Positive;
import static org.microg.tools.selfcheck.SelfCheckGroup.Result.Unknown;
public abstract class AbstractSelfCheckFragment extends Fragment {
private static final String TAG = "SelfCheck";
private ViewGroup root;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View scrollRoot = inflater.inflate(R.layout.self_check, container, false);
root = (ViewGroup) scrollRoot.findViewById(R.id.self_check_root);
reset(inflater);
return scrollRoot;
}
protected abstract void prepareSelfCheckList(List<SelfCheckGroup> checks);
protected void reset(LayoutInflater inflater) {
List<SelfCheckGroup> selfCheckGroupList = new ArrayList<SelfCheckGroup>();
prepareSelfCheckList(selfCheckGroupList);
root.removeAllViews();
for (SelfCheckGroup group : selfCheckGroupList) {
View groupView = inflater.inflate(R.layout.self_check_group, root, false);
((TextView) groupView.findViewById(android.R.id.title)).setText(group.getGroupName(getContext()));
final ViewGroup viewGroup = (ViewGroup) groupView.findViewById(R.id.group_content);
final SelfCheckGroup.ResultCollector collector = new GroupResultCollector(viewGroup);
try {
group.doChecks(getContext(), collector);
} catch (Exception e) {
Log.w(TAG, "Failed during check " + group.getGroupName(getContext()), e);
collector.addResult("Self-check failed:", Negative, "An exception occurred during self-check. Please report this issue.");
}
root.addView(groupView);
}
}
private class GroupResultCollector implements SelfCheckGroup.ResultCollector {
private final ViewGroup viewGroup;
public GroupResultCollector(ViewGroup viewGroup) {
this.viewGroup = viewGroup;
}
@Override
public void addResult(final String name, final SelfCheckGroup.Result result, final String resolution) {
addResult(name, result, resolution, null);
}
@Override
public void addResult(final String name, final SelfCheckGroup.Result result, final String resolution,
final SelfCheckGroup.CheckResolver resolver) {
if (result == null || getActivity() == null) return;
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
View resultEntry = LayoutInflater.from(getContext()).inflate(R.layout.self_check_entry, viewGroup, false);
((TextView) resultEntry.findViewById(R.id.self_check_name)).setText(name);
resultEntry.findViewById(R.id.self_check_result).setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
return true;
}
});
if (result == Positive) {
((CheckBox) resultEntry.findViewById(R.id.self_check_result)).setChecked(true);
resultEntry.findViewById(R.id.self_check_resolution).setVisibility(GONE);
} else {
((TextView) resultEntry.findViewById(R.id.self_check_resolution)).setText(resolution);
if (result == Unknown) {
resultEntry.findViewById(R.id.self_check_result).setVisibility(INVISIBLE);
}
if (resolver != null) {
resultEntry.setClickable(true);
resultEntry.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
resolver.tryResolve(AbstractSelfCheckFragment.this);
}
});
}
}
viewGroup.addView(resultEntry);
}
});
}
}
}

View file

@ -0,0 +1,77 @@
package org.microg.tools.ui;
import android.os.Bundle;
import android.view.MenuItem;
import android.view.ViewGroup;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentTransaction;
public abstract class AbstractSettingsActivity extends AppCompatActivity {
protected boolean showHomeAsUp = false;
protected int preferencesResource = 0;
private ViewGroup customBarContainer;
protected int customBarLayout = 0;
protected SwitchBar switchBar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.settings_activity);
if (showHomeAsUp) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
switchBar = (SwitchBar) findViewById(R.id.switch_bar);
customBarContainer = (ViewGroup) findViewById(R.id.custom_bar);
if (customBarLayout != 0) {
customBarContainer.addView(getLayoutInflater().inflate(customBarLayout, customBarContainer, false));
}
getSupportFragmentManager().beginTransaction()
.replace(R.id.content_wrapper, getFragment())
.commit();
}
public void setCustomBarLayout(int layout) {
customBarLayout = layout;
if (customBarContainer != null) {
customBarContainer.removeAllViews();
customBarContainer.addView(getLayoutInflater().inflate(customBarLayout, customBarContainer, false));
}
}
public SwitchBar getSwitchBar() {
return switchBar;
}
public void replaceFragment(Fragment fragment) {
getSupportFragmentManager().beginTransaction()
.addToBackStack("root")
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
.replace(R.id.content_wrapper, fragment)
.commit();
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
finish();
return true;
}
return super.onOptionsItemSelected(item);
}
protected Fragment getFragment() {
if (preferencesResource == 0) {
throw new IllegalStateException("Neither preferencesResource given, nor overriden getFragment()");
}
ResourceSettingsFragment fragment = new ResourceSettingsFragment();
Bundle b = new Bundle();
b.putInt(ResourceSettingsFragment.EXTRA_PREFERENCE_RESOURCE, preferencesResource);
fragment.setArguments(b);
return fragment;
}
}

View file

@ -0,0 +1,38 @@
/*
* Copyright (C) 2013-2017 microG Project Team
*
* 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 org.microg.tools.ui;
import androidx.fragment.app.DialogFragment;
import androidx.preference.Preference;
import androidx.preference.PreferenceFragmentCompat;
public abstract class AbstractSettingsFragment extends PreferenceFragmentCompat {
private static final String TAG = AbstractSettingsFragment.class.getSimpleName();
private static final String DIALOG_FRAGMENT_TAG = "androidx.preference.PreferenceFragment.DIALOG";
@Override
public void onDisplayPreferenceDialog(Preference preference) {
if (preference instanceof DialogPreference) {
DialogFragment f = DialogPreference.DialogPreferenceCompatDialogFragment.newInstance(preference.getKey());
f.setTargetFragment(this, 0);
f.show(getFragmentManager(), DIALOG_FRAGMENT_TAG);
} else {
super.onDisplayPreferenceDialog(preference);
}
}
}

View file

@ -0,0 +1,338 @@
/*
* Copyright (C) 2013-2017 microG Project Team
*
* 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 org.microg.tools.ui;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.DrawableRes;
import androidx.annotation.PluralsRes;
import androidx.annotation.StringRes;
import androidx.core.content.res.ResourcesCompat;
public class Condition {
@DrawableRes
private final int iconRes;
private final Drawable icon;
@StringRes
private final int titleRes;
@PluralsRes
private final int titlePluralsRes;
private final CharSequence title;
@StringRes
private final int summaryRes;
@PluralsRes
private final int summaryPluralsRes;
private final CharSequence summary;
@StringRes
private final int firstActionTextRes;
@PluralsRes
private final int firstActionPluralsRes;
private final CharSequence firstActionText;
private final View.OnClickListener firstActionListener;
@StringRes
private final int secondActionTextRes;
@PluralsRes
private final int secondActionPluralsRes;
private final CharSequence secondActionText;
private final View.OnClickListener secondActionListener;
private final Evaluation evaluation;
private boolean evaluated = false;
private boolean evaluating = false;
private int evaluatedPlurals = -1;
private boolean active;
Condition(Builder builder) {
icon = builder.icon;
title = builder.title;
summary = builder.summary;
firstActionText = builder.firstActionText;
firstActionListener = builder.firstActionListener;
secondActionText = builder.secondActionText;
secondActionListener = builder.secondActionListener;
summaryRes = builder.summaryRes;
iconRes = builder.iconRes;
firstActionTextRes = builder.firstActionTextRes;
secondActionTextRes = builder.secondActionTextRes;
titleRes = builder.titleRes;
evaluation = builder.evaluation;
titlePluralsRes = builder.titlePluralsRes;
summaryPluralsRes = builder.summaryPluralsRes;
firstActionPluralsRes = builder.firstActionPluralsRes;
secondActionPluralsRes = builder.secondActionPluralsRes;
}
View createView(final Context context, ViewGroup container) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = inflater.inflate(R.layout.condition_card, container, false);
Drawable icon = getIcon(context);
if (icon != null)
((ImageView) view.findViewById(android.R.id.icon)).setImageDrawable(icon);
((TextView) view.findViewById(android.R.id.title)).setText(getTitle(context));
((TextView) view.findViewById(android.R.id.summary)).setText(getSummary(context));
Button first = (Button) view.findViewById(R.id.first_action);
first.setText(getFirstActionText(context));
first.setOnClickListener(getFirstActionListener());
CharSequence secondActionText = getSecondActionText(context);
if (secondActionText != null) {
Button second = (Button) view.findViewById(R.id.second_action);
second.setText(secondActionText);
second.setOnClickListener(getSecondActionListener());
second.setVisibility(View.VISIBLE);
}
final View detailGroup = view.findViewById(R.id.detail_group);
final ImageView expandIndicator = (ImageView) view.findViewById(R.id.expand_indicator);
View.OnClickListener expandListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
if (detailGroup.getVisibility() == View.VISIBLE) {
expandIndicator.setImageDrawable(ResourcesCompat.getDrawable(context.getResources(), R.drawable.ic_expand_more, context.getTheme()));
detailGroup.setVisibility(View.GONE);
} else {
expandIndicator.setImageDrawable(ResourcesCompat.getDrawable(context.getResources(), R.drawable.ic_expand_less, context.getTheme()));
detailGroup.setVisibility(View.VISIBLE);
}
}
};
view.findViewById(R.id.collapsed_group).setOnClickListener(expandListener);
expandIndicator.setOnClickListener(expandListener);
view.setTag(this);
return view;
}
public Drawable getIcon(Context context) {
if (iconRes != 0) {
return ResourcesCompat.getDrawable(context.getResources(), iconRes, context.getTheme());
}
return icon;
}
public CharSequence getTitle(Context context) {
if (titleRes != 0) {
return context.getString(titleRes);
}
if (titlePluralsRes != 0) {
return context.getResources().getQuantityString(titlePluralsRes, evaluatedPlurals);
}
return title;
}
public CharSequence getSummary(Context context) {
if (summaryRes != 0) {
return context.getString(summaryRes);
}
if (summaryPluralsRes != 0) {
return context.getResources().getQuantityString(summaryPluralsRes, evaluatedPlurals);
}
return summary;
}
public View.OnClickListener getFirstActionListener() {
return firstActionListener;
}
public CharSequence getFirstActionText(Context context) {
if (firstActionTextRes != 0) {
return context.getString(firstActionTextRes);
}
if (firstActionPluralsRes != 0) {
return context.getResources().getQuantityString(firstActionPluralsRes, evaluatedPlurals);
}
return firstActionText;
}
public View.OnClickListener getSecondActionListener() {
return secondActionListener;
}
public CharSequence getSecondActionText(Context context) {
if (secondActionTextRes != 0) {
return context.getString(secondActionTextRes);
}
if (secondActionPluralsRes != 0) {
return context.getResources().getQuantityString(secondActionPluralsRes, evaluatedPlurals);
}
return secondActionText;
}
public synchronized boolean willBeEvaluating() {
if (!evaluating && !evaluated && evaluation != null) {
return evaluating = true;
} else {
return false;
}
}
public boolean isEvaluated() {
return evaluated || evaluation == null;
}
public synchronized void evaluate(Context context) {
active = evaluation == null || evaluation.isActive(context);
evaluatedPlurals = evaluation.getPluralsCount();
evaluated = true;
evaluating = false;
}
public boolean isActive(Context context) {
if (!evaluated && evaluation != null) evaluate(context);
return active;
}
public void resetEvaluated() {
this.evaluated = false;
}
public static abstract class Evaluation {
public abstract boolean isActive(Context context);
public int getPluralsCount() {
return 1;
}
}
public static class Builder {
@DrawableRes
private int iconRes;
private Drawable icon;
@StringRes
private int titleRes;
@PluralsRes
private int titlePluralsRes;
private CharSequence title;
@StringRes
private int summaryRes;
@PluralsRes
private int summaryPluralsRes;
private CharSequence summary;
@StringRes
private int firstActionTextRes;
@PluralsRes
private int firstActionPluralsRes;
private CharSequence firstActionText;
private View.OnClickListener firstActionListener;
@StringRes
private int secondActionTextRes;
@PluralsRes
private int secondActionPluralsRes;
private CharSequence secondActionText;
private View.OnClickListener secondActionListener;
private Evaluation evaluation;
public Builder() {
}
public Builder icon(Drawable val) {
icon = val;
return this;
}
public Builder icon(@DrawableRes int val) {
iconRes = val;
return this;
}
public Builder title(CharSequence val) {
title = val;
return this;
}
public Builder title(@StringRes int val) {
titleRes = val;
return this;
}
public Builder titlePlurals(@PluralsRes int val) {
titlePluralsRes = val;
return this;
}
public Builder summary(CharSequence val) {
summary = val;
return this;
}
public Builder summary(@StringRes int val) {
summaryRes = val;
return this;
}
public Builder summaryPlurals(@PluralsRes int val) {
summaryPluralsRes = val;
return this;
}
public Builder firstAction(CharSequence text, View.OnClickListener listener) {
firstActionText = text;
firstActionListener = listener;
return this;
}
public Builder firstAction(@StringRes int val, View.OnClickListener listener) {
firstActionTextRes = val;
firstActionListener = listener;
return this;
}
public Builder firstActionPlurals(@PluralsRes int val, View.OnClickListener listener) {
firstActionPluralsRes = val;
firstActionListener = listener;
return this;
}
public Builder secondAction(CharSequence text, View.OnClickListener listener) {
secondActionText = text;
secondActionListener = listener;
return this;
}
public Builder secondAction(@StringRes int val, View.OnClickListener listener) {
secondActionTextRes = val;
secondActionListener = listener;
return this;
}
public Builder secondActionPlurals(@PluralsRes int val, View.OnClickListener listener) {
secondActionPluralsRes = val;
secondActionListener = listener;
return this;
}
public Builder evaluation(Evaluation evaluation) {
this.evaluation = evaluation;
return this;
}
public Condition build() {
return new Condition(this);
}
}
}

View file

@ -0,0 +1,114 @@
/*
* Copyright (C) 2013-2017 microG Project Team
*
* 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 org.microg.tools.ui;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import androidx.fragment.app.DialogFragment;
import androidx.preference.Preference;
import androidx.preference.PreferenceDialogFragmentCompat;
import androidx.preference.PreferenceFragmentCompat;
import androidx.preference.PreferenceViewHolder;
public class DialogPreference extends androidx.preference.DialogPreference implements PreferenceFragmentCompat.OnPreferenceDisplayDialogCallback {
private static final String DIALOG_FRAGMENT_TAG =
"android.support.v7.preference.PreferenceFragment.DIALOG";
public DialogPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
public DialogPreference(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public DialogPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
public DialogPreference(Context context) {
super(context);
}
protected View onCreateDialogView() {
return null;
}
/**
* Called when the dialog is dismissed and should be used to save data to
* the {@link SharedPreferences}.
*
* @param positiveResult Whether the positive button was clicked (true), or
* the negative button was clicked or the dialog was canceled (false).
*/
protected void onDialogClosed(boolean positiveResult) {
}
@Override
public boolean onPreferenceDisplayDialog(PreferenceFragmentCompat caller, Preference pref) {
DialogPreferenceCompatDialogFragment fragment = new DialogPreferenceCompatDialogFragment();
fragment.setTargetFragment(caller, 0);
fragment.show(caller.getFragmentManager(), DIALOG_FRAGMENT_TAG);
return true;
}
@Override
public void onBindViewHolder(PreferenceViewHolder view) {
super.onBindViewHolder(view);
ViewGroup.LayoutParams layoutParams = view.findViewById(R.id.icon_frame).getLayoutParams();
if (layoutParams instanceof LinearLayout.LayoutParams) {
if (((LinearLayout.LayoutParams) layoutParams).leftMargin < 0) {
((LinearLayout.LayoutParams) layoutParams).leftMargin = 0;
}
}
}
public static class DialogPreferenceCompatDialogFragment extends PreferenceDialogFragmentCompat {
@Override
protected View onCreateDialogView(Context context) {
if (getPreference() instanceof DialogPreference) {
View view = ((DialogPreference) getPreference()).onCreateDialogView();
if (view != null) return view;
}
return super.onCreateDialogView(context);
}
@Override
public void onDialogClosed(boolean positiveResult) {
if (getPreference() instanceof DialogPreference) {
((DialogPreference) getPreference()).onDialogClosed(positiveResult);
}
}
public static DialogFragment newInstance(String key) {
final DialogPreferenceCompatDialogFragment fragment = new DialogPreferenceCompatDialogFragment();
final Bundle b = new Bundle(1);
b.putString(ARG_KEY, key);
fragment.setArguments(b);
return fragment;
}
}
}

View file

@ -0,0 +1,81 @@
/*
* Copyright (C) 2014 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 org.microg.tools.ui;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.preference.Preference;
import androidx.preference.PreferenceViewHolder;
/**
* A preference item that can dim the icon when it's disabled, either directly or because its parent
* is disabled.
*/
public class DimmableIconPreference extends Preference {
private static final int ICON_ALPHA_ENABLED = 255;
private static final int ICON_ALPHA_DISABLED = 102;
private final CharSequence mContentDescription;
public DimmableIconPreference(Context context) {
this(context, (AttributeSet) null);
}
public DimmableIconPreference(Context context, AttributeSet attrs) {
super(context, attrs);
mContentDescription = null;
}
public DimmableIconPreference(Context context, CharSequence contentDescription) {
super(context);
mContentDescription = contentDescription;
}
protected boolean shouldDimIcon() {
return !isEnabled();
}
private void dimIcon(boolean dimmed) {
Drawable icon = getIcon();
if (icon != null) {
icon.mutate().setAlpha(dimmed ? ICON_ALPHA_DISABLED : ICON_ALPHA_ENABLED);
setIcon(icon);
}
}
@Override
public void onBindViewHolder(PreferenceViewHolder view) {
super.onBindViewHolder(view);
if (!TextUtils.isEmpty(mContentDescription)) {
final TextView titleView = (TextView) view.findViewById(android.R.id.title);
titleView.setContentDescription(mContentDescription);
}
ViewGroup.LayoutParams layoutParams = view.findViewById(R.id.icon_frame).getLayoutParams();
if (layoutParams instanceof LinearLayout.LayoutParams) {
if (((LinearLayout.LayoutParams) layoutParams).leftMargin < 0) {
((LinearLayout.LayoutParams) layoutParams).leftMargin = 0;
}
}
dimIcon(shouldDimIcon());
}
}

View file

@ -0,0 +1,52 @@
/*
* Copyright (C) 2017 microG Project Team
*
* 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 org.microg.tools.ui;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.TextView;
import androidx.preference.Preference;
import androidx.preference.PreferenceViewHolder;
public class LongTextPreference extends Preference {
public LongTextPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
public LongTextPreference(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public LongTextPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
public LongTextPreference(Context context) {
super(context);
}
@Override
public void onBindViewHolder(PreferenceViewHolder holder) {
super.onBindViewHolder(holder);
TextView view = (TextView) holder.findViewById(android.R.id.summary);
if (view != null) {
view.setMaxLines(Integer.MAX_VALUE);
}
}
}

View file

@ -0,0 +1,46 @@
/*
* Copyright (C) 2017 microG Project Team
*
* 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 org.microg.tools.ui;
import android.annotation.SuppressLint;
import android.content.Context;
import android.util.AttributeSet;
import androidx.core.content.res.TypedArrayUtils;
import androidx.preference.CheckBoxPreference;
public class RadioButtonPreference extends CheckBoxPreference {
public RadioButtonPreference(Context context, AttributeSet attrs, int defStyleAttr) {
this(context, attrs, defStyleAttr, 0);
}
public RadioButtonPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
setWidgetLayoutResource(R.layout.preference_widget_radiobutton);
}
@SuppressLint("RestrictedApi")
public RadioButtonPreference(Context context, AttributeSet attrs) {
this(context, attrs, TypedArrayUtils.getAttr(context, R.attr.checkBoxPreferenceStyle,
android.R.attr.checkBoxPreferenceStyle));
}
public RadioButtonPreference(Context context) {
this(context, null);
}
}

View file

@ -0,0 +1,39 @@
/*
* Copyright (C) 2017 microG Project Team
*
* 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 org.microg.tools.ui;
import android.os.Bundle;
import androidx.annotation.Nullable;
public class ResourceSettingsFragment extends AbstractSettingsFragment {
public static final String EXTRA_PREFERENCE_RESOURCE = "preferencesResource";
protected int preferencesResource;
@Override
public void onCreatePreferences(@Nullable Bundle savedInstanceState, String rootKey) {
Bundle b = getArguments();
if (b != null) {
preferencesResource = b.getInt(EXTRA_PREFERENCE_RESOURCE, preferencesResource);
}
if (preferencesResource != 0) {
addPreferencesFromResource(preferencesResource);
}
}
}

View file

@ -0,0 +1,265 @@
/*
* Copyright (C) 2014 The Android Open Source Project
* Copyright (C) 2014-2017 microG Project Team
*
* 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 org.microg.tools.ui;
import android.content.Context;
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
import android.text.style.TextAppearanceSpan;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.CompoundButton;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.appcompat.widget.SwitchCompat;
import java.util.ArrayList;
import static android.os.Build.VERSION.SDK_INT;
public class SwitchBar extends LinearLayout implements CompoundButton.OnCheckedChangeListener,
View.OnClickListener {
public static interface OnSwitchChangeListener {
/**
* Called when the checked state of the Switch has changed.
*
* @param switchView The Switch view whose state has changed.
* @param isChecked The new checked state of switchView.
*/
void onSwitchChanged(SwitchCompat switchView, boolean isChecked);
}
private final TextAppearanceSpan mSummarySpan;
private ToggleSwitch mSwitch;
private TextView mTextView;
private String mLabel;
private String mSummary;
private ArrayList<OnSwitchChangeListener> mSwitchChangeListeners =
new ArrayList<OnSwitchChangeListener>();
public SwitchBar(Context context) {
this(context, null);
}
public SwitchBar(Context context, AttributeSet attrs) {
super(context, attrs);
LayoutInflater.from(context).inflate(R.layout.switch_bar, this);
mTextView = (TextView) findViewById(R.id.switch_text);
if (SDK_INT > Build.VERSION_CODES.JELLY_BEAN) {
mTextView.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO);
}
mLabel = getResources().getString(R.string.abc_capital_off);
mSummarySpan = new TextAppearanceSpan(context, androidx.appcompat.R.style.TextAppearance_AppCompat_Widget_Switch);
updateText();
mSwitch = (ToggleSwitch) findViewById(R.id.switch_widget);
// Prevent onSaveInstanceState() to be called as we are managing the state of the Switch
// on our own
mSwitch.setSaveEnabled(false);
if (SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
mSwitch.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO);
}
addOnSwitchChangeListener(new OnSwitchChangeListener() {
@Override
public void onSwitchChanged(SwitchCompat switchView, boolean isChecked) {
setTextViewLabel(isChecked);
}
});
setOnClickListener(this);
// Default is hide
setVisibility(View.GONE);
}
public void setTextViewLabel(boolean isChecked) {
mLabel = getResources()
.getString(isChecked ? R.string.abc_capital_on : R.string.abc_capital_off);
updateText();
}
public void setSummary(String summary) {
mSummary = summary;
updateText();
}
private void updateText() {
if (TextUtils.isEmpty(mSummary)) {
mTextView.setText(mLabel);
return;
}
final SpannableStringBuilder ssb = new SpannableStringBuilder(mLabel).append('\n');
final int start = ssb.length();
ssb.append(mSummary);
ssb.setSpan(mSummarySpan, start, ssb.length(), 0);
mTextView.setText(ssb);
}
public void setChecked(boolean checked) {
setTextViewLabel(checked);
mSwitch.setChecked(checked);
}
public void setCheckedInternal(boolean checked) {
setTextViewLabel(checked);
mSwitch.setCheckedInternal(checked);
}
public boolean isChecked() {
return mSwitch.isChecked();
}
public void setEnabled(boolean enabled) {
super.setEnabled(enabled);
mTextView.setEnabled(enabled);
mSwitch.setEnabled(enabled);
}
public final ToggleSwitch getSwitch() {
return mSwitch;
}
public void show() {
if (!isShowing()) {
setVisibility(View.VISIBLE);
mSwitch.setOnCheckedChangeListener(this);
}
}
public void hide() {
if (isShowing()) {
setVisibility(View.GONE);
mSwitch.setOnCheckedChangeListener(null);
}
}
public boolean isShowing() {
return (getVisibility() == View.VISIBLE);
}
@Override
public void onClick(View v) {
final boolean isChecked = !mSwitch.isChecked();
setChecked(isChecked);
}
public void propagateChecked(boolean isChecked) {
final int count = mSwitchChangeListeners.size();
for (int n = 0; n < count; n++) {
mSwitchChangeListeners.get(n).onSwitchChanged(mSwitch, isChecked);
}
}
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
propagateChecked(isChecked);
}
public void addOnSwitchChangeListener(OnSwitchChangeListener listener) {
if (mSwitchChangeListeners.contains(listener)) {
throw new IllegalStateException("Cannot add twice the same OnSwitchChangeListener");
}
mSwitchChangeListeners.add(listener);
}
public void removeOnSwitchChangeListener(OnSwitchChangeListener listener) {
if (!mSwitchChangeListeners.contains(listener)) {
throw new IllegalStateException("Cannot remove OnSwitchChangeListener");
}
mSwitchChangeListeners.remove(listener);
}
static class SavedState extends BaseSavedState {
boolean checked;
boolean visible;
SavedState(Parcelable superState) {
super(superState);
}
/**
* Constructor called from {@link #CREATOR}
*/
private SavedState(Parcel in) {
super(in);
checked = (Boolean) in.readValue(Boolean.class.getClassLoader());
visible = (Boolean) in.readValue(Boolean.class.getClassLoader());
}
@Override
public void writeToParcel(Parcel out, int flags) {
super.writeToParcel(out, flags);
out.writeValue(checked);
out.writeValue(visible);
}
@Override
public String toString() {
return "SwitchBar.SavedState{"
+ Integer.toHexString(System.identityHashCode(this))
+ " checked=" + checked
+ " visible=" + visible + "}";
}
public static final Parcelable.Creator<SavedState> CREATOR
= new Parcelable.Creator<SavedState>() {
public SavedState createFromParcel(Parcel in) {
return new SavedState(in);
}
public SavedState[] newArray(int size) {
return new SavedState[size];
}
};
}
@Override
public Parcelable onSaveInstanceState() {
Parcelable superState = super.onSaveInstanceState();
SavedState ss = new SavedState(superState);
ss.checked = mSwitch.isChecked();
ss.visible = isShowing();
return ss;
}
@Override
public void onRestoreInstanceState(Parcelable state) {
SavedState ss = (SavedState) state;
super.onRestoreInstanceState(ss.getSuperState());
mSwitch.setCheckedInternal(ss.checked);
setTextViewLabel(ss.checked);
setVisibility(ss.visible ? View.VISIBLE : View.GONE);
mSwitch.setOnCheckedChangeListener(ss.visible ? this : null);
requestLayout();
}
}

View file

@ -0,0 +1,71 @@
/*
* Copyright (C) 2017 microG Project Team
*
* 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 org.microg.tools.ui;
import android.os.Bundle;
import androidx.appcompat.widget.SwitchCompat;
public abstract class SwitchBarResourceSettingsFragment extends ResourceSettingsFragment implements SwitchBar.OnSwitchChangeListener {
protected SwitchBar switchBar;
private SwitchCompat switchCompat;
private boolean listenerSetup = false;
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
AbstractSettingsActivity activity = (AbstractSettingsActivity) getActivity();
switchBar = activity.getSwitchBar();
switchBar.show();
switchCompat = switchBar.getSwitch();
}
@Override
public void onDestroyView() {
super.onDestroyView();
switchBar.hide();
}
@Override
public void onResume() {
super.onResume();
if (!listenerSetup) {
switchBar.addOnSwitchChangeListener(this);
listenerSetup = true;
}
}
@Override
public void onPause() {
if (listenerSetup) {
switchBar.removeOnSwitchChangeListener(this);
listenerSetup = false;
}
super.onPause();
}
@Override
public void onSwitchChanged(SwitchCompat switchView, boolean isChecked) {
if (switchView == switchCompat) {
onSwitchBarChanged(isChecked);
}
}
public abstract void onSwitchBarChanged(boolean isChecked);
}

View file

@ -0,0 +1,45 @@
package org.microg.tools.ui;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.TypedValue;
import androidx.core.graphics.drawable.DrawableCompat;
import androidx.preference.PreferenceViewHolder;
import static android.os.Build.VERSION.SDK_INT;
import static android.os.Build.VERSION_CODES.LOLLIPOP;
public class TintIconPreference extends DimmableIconPreference {
public TintIconPreference(Context context) {
this(context, (AttributeSet) null);
}
public TintIconPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
private static int getThemeAccentColor(Context context) {
int colorAttr;
if (SDK_INT >= LOLLIPOP) {
colorAttr = android.R.attr.colorAccent;
} else {
//Get colorAccent defined for AppCompat
colorAttr = context.getResources().getIdentifier("colorAccent", "attr", context.getPackageName());
}
TypedValue outValue = new TypedValue();
context.getTheme().resolveAttribute(colorAttr, outValue, true);
return outValue.data;
}
@Override
public void onBindViewHolder(PreferenceViewHolder view) {
super.onBindViewHolder(view);
Drawable icon = getIcon();
if (icon != null) {
DrawableCompat.setTint(icon, getThemeAccentColor(getContext()));
}
}
}

View file

@ -0,0 +1,63 @@
/*
* Copyright (C) 2014 The Android Open Source Project
* Copyright (C) 2014-2017 microG Project Team
*
* 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 org.microg.tools.ui;
import android.annotation.SuppressLint;
import android.content.Context;
import android.util.AttributeSet;
import androidx.appcompat.widget.SwitchCompat;
@SuppressLint("NewApi")
public class ToggleSwitch extends SwitchCompat {
private ToggleSwitch.OnBeforeCheckedChangeListener mOnBeforeListener;
public interface OnBeforeCheckedChangeListener {
boolean onBeforeCheckedChanged(ToggleSwitch toggleSwitch, boolean checked);
}
public ToggleSwitch(Context context) {
super(context);
}
public ToggleSwitch(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ToggleSwitch(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public void setOnBeforeCheckedChangeListener(OnBeforeCheckedChangeListener listener) {
mOnBeforeListener = listener;
}
@Override
public void setChecked(boolean checked) {
if (mOnBeforeListener != null
&& mOnBeforeListener.onBeforeCheckedChanged(this, checked)) {
return;
}
super.setChecked(checked);
}
public void setCheckedInternal(boolean checked) {
super.setChecked(checked);
}
}

Some files were not shown because too many files have changed in this diff Show more