49 changed files with 2275 additions and 1 deletions
@ -0,0 +1,111 @@
|
||||
/* |
||||
* SPDX-FileCopyrightText: 2019, microG Project Team |
||||
* SPDX-License-Identifier: Apache-2.0 |
||||
*/ |
||||
|
||||
|
||||
apply plugin: 'com.android.application' |
||||
apply plugin: 'kotlin-android' |
||||
apply plugin: 'kotlin-kapt' |
||||
apply plugin: 'kotlin-android-extensions' |
||||
apply plugin: 'maven-publish' |
||||
apply plugin: 'signing' |
||||
|
||||
String getMyVersionName() { |
||||
def stdout = new ByteArrayOutputStream() |
||||
if (rootProject.file("gradlew").exists()) |
||||
exec { commandLine 'git', 'describe', '--tags', '--always', '--dirty'; standardOutput = stdout } |
||||
else // automatic build system, don't tag dirty |
||||
exec { commandLine 'git', 'describe', '--tags', '--always'; standardOutput = stdout } |
||||
return stdout.toString().trim().substring(1) |
||||
} |
||||
|
||||
int getMyVersionCode() { |
||||
def stdout = new ByteArrayOutputStream() |
||||
exec { |
||||
commandLine 'git', 'rev-list', '--count', "HEAD" |
||||
standardOutput = stdout |
||||
} |
||||
return Integer.parseInt(stdout.toString().trim()) |
||||
} |
||||
|
||||
android { |
||||
compileSdkVersion androidCompileSdk |
||||
buildToolsVersion "$androidBuildVersionTools" |
||||
dataBinding { |
||||
enabled = true |
||||
} |
||||
|
||||
defaultConfig { |
||||
versionName getMyVersionName() |
||||
versionCode(20000 + getMyVersionCode()) |
||||
minSdkVersion Math.max(androidMinSdk, 14) |
||||
targetSdkVersion androidTargetSdk |
||||
} |
||||
|
||||
sourceSets { |
||||
main.java.srcDirs += 'src/main/kotlin' |
||||
} |
||||
|
||||
flavorDimensions 'default' |
||||
productFlavors { |
||||
NetworkLocation { |
||||
applicationId = 'com.google.android.gms' |
||||
minSdkVersion 19 |
||||
dimension 'default' |
||||
} |
||||
LegacyNetworkLocation { |
||||
applicationId = 'com.google.android.location' |
||||
dimension 'default' |
||||
} |
||||
UnifiedNlp { |
||||
applicationId = 'org.microg.nlp' |
||||
dimension 'default' |
||||
} |
||||
} |
||||
|
||||
compileOptions { |
||||
sourceCompatibility = 1.8 |
||||
targetCompatibility = 1.8 |
||||
} |
||||
|
||||
kotlinOptions { |
||||
jvmTarget = "1.8" |
||||
} |
||||
|
||||
lintOptions { |
||||
warning "MissingTranslation" |
||||
} |
||||
} |
||||
|
||||
apply from: "../gradle/androidJars.gradle" |
||||
|
||||
dependencies { |
||||
implementation project(':api') |
||||
implementation project(':geocode-v1') |
||||
implementation project(':location-v2') |
||||
implementation project(':location-v3') |
||||
implementation project(':service') |
||||
api project(':client') |
||||
api project(':ui') |
||||
|
||||
// Kotlin |
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion" |
||||
|
||||
// AndroidX UI |
||||
implementation "androidx.appcompat:appcompat:$appcompatVersion" |
||||
implementation "androidx.preference:preference:$preferenceVersion" |
||||
implementation "androidx.lifecycle:lifecycle-service:$lifecycleVersion" |
||||
|
||||
// Navigation |
||||
implementation "androidx.navigation:navigation-fragment:$navigationVersion" |
||||
implementation "androidx.navigation:navigation-ui:$navigationVersion" |
||||
implementation "androidx.navigation:navigation-fragment-ktx:$navigationVersion" |
||||
implementation "androidx.navigation:navigation-ui-ktx:$navigationVersion" |
||||
} |
||||
|
||||
afterEvaluate { |
||||
android.applicationVariants.all { variant -> |
||||
variant.resValue 'string', 'application_id', variant.applicationId |
||||
} |
||||
} |
@ -0,0 +1,54 @@
|
||||
<?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 xmlns:android="http://schemas.android.com/apk/res/android" |
||||
xmlns:tools="http://schemas.android.com/tools" |
||||
package="org.microg.nlp.app"> |
||||
|
||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> |
||||
|
||||
<application |
||||
android:allowBackup="true" |
||||
android:icon="@mipmap/ic_nlp_app" |
||||
android:label="@string/nlp_app_name" |
||||
android:theme="@style/Theme.AppCompat.DayNight"> |
||||
|
||||
<activity |
||||
android:name="org.microg.nlp.ui.BackendSettingsActivity" |
||||
android:process=":ui" /> |
||||
|
||||
<activity |
||||
android:name="org.microg.nlp.app.SettingsActivity" |
||||
android:icon="@mipmap/ic_nlp_settings" |
||||
android:label="@string/nlp_app_name" |
||||
android:process=":ui"> |
||||
<intent-filter> |
||||
<action android:name="android.intent.action.MAIN" /> |
||||
<category android:name="android.intent.category.LAUNCHER" /> |
||||
</intent-filter> |
||||
</activity> |
||||
|
||||
<activity |
||||
android:name="org.microg.nlp.app.SelfCheckFragment$AsActivity" |
||||
android:label="@string/self_check_title" |
||||
android:process=":ui" /> |
||||
|
||||
<activity |
||||
android:name="org.microg.nlp.app.AboutFragment$AsActivity" |
||||
android:label="@string/pref_about_title" |
||||
android:process=":ui" /> |
||||
</application> |
||||
</manifest> |
@ -0,0 +1,45 @@
|
||||
/* |
||||
* 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.nlp.app; |
||||
|
||||
import androidx.fragment.app.Fragment; |
||||
|
||||
import org.microg.nlp.app.BuildConfig; |
||||
|
||||
import org.microg.nlp.app.tools.ui.AbstractAboutFragment; |
||||
import org.microg.nlp.app.tools.ui.AbstractSettingsActivity; |
||||
|
||||
import java.util.List; |
||||
|
||||
public class AboutFragment extends AbstractAboutFragment { |
||||
|
||||
@Override |
||||
protected void collectLibraries(List<AbstractAboutFragment.Library> libraries) { |
||||
libraries.add(new AbstractAboutFragment.Library("org.microg.nlp.service", "UnifiedNlp", "Apache License 2.0, microG Team")); |
||||
} |
||||
|
||||
public static class AsActivity extends AbstractSettingsActivity { |
||||
public AsActivity() { |
||||
showHomeAsUp = true; |
||||
} |
||||
|
||||
@Override |
||||
protected Fragment getFragment() { |
||||
return new AboutFragment(); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,22 @@
|
||||
/* |
||||
* 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.nlp.app; |
||||
|
||||
import android.app.Activity; |
||||
|
||||
public class LocationSettingsActivity extends Activity { |
||||
} |
@ -0,0 +1,79 @@
|
||||
/* |
||||
* 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.nlp.app; |
||||
|
||||
import android.content.Context; |
||||
import android.content.Intent; |
||||
import android.content.pm.PackageManager; |
||||
import android.content.pm.PermissionGroupInfo; |
||||
import android.content.pm.PermissionInfo; |
||||
import android.net.Uri; |
||||
import android.os.Build; |
||||
import android.provider.Settings; |
||||
import android.util.Log; |
||||
import android.view.LayoutInflater; |
||||
|
||||
import androidx.annotation.NonNull; |
||||
import androidx.fragment.app.Fragment; |
||||
|
||||
import org.microg.nlp.app.tools.selfcheck.PermissionCheckGroup; |
||||
import org.microg.nlp.app.tools.selfcheck.SelfCheckGroup; |
||||
import org.microg.nlp.app.tools.ui.AbstractSelfCheckFragment; |
||||
import org.microg.nlp.app.tools.ui.AbstractSettingsActivity; |
||||
import org.microg.nlp.app.tools.selfcheck.NlpOsCompatChecks; |
||||
import org.microg.nlp.app.tools.selfcheck.NlpStatusChecks; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
|
||||
import static android.Manifest.permission.ACCESS_COARSE_LOCATION; |
||||
import static android.os.Build.VERSION.SDK_INT; |
||||
import static android.os.Build.VERSION_CODES.LOLLIPOP_MR1; |
||||
|
||||
public class SelfCheckFragment extends AbstractSelfCheckFragment { |
||||
|
||||
@Override |
||||
protected void prepareSelfCheckList(List<SelfCheckGroup> checks) { |
||||
if (SDK_INT > LOLLIPOP_MR1) { |
||||
checks.add(new PermissionCheckGroup(ACCESS_COARSE_LOCATION)); |
||||
} |
||||
checks.add(new NlpOsCompatChecks()); |
||||
checks.add(new NlpStatusChecks()); |
||||
} |
||||
|
||||
@Override |
||||
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { |
||||
reset(LayoutInflater.from(getContext())); |
||||
} |
||||
|
||||
@Override |
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) { |
||||
reset(LayoutInflater.from(getContext())); |
||||
super.onActivityResult(requestCode, resultCode, data); |
||||
} |
||||
|
||||
public static class AsActivity extends AbstractSettingsActivity { |
||||
public AsActivity() { |
||||
showHomeAsUp = true; |
||||
} |
||||
|
||||
@Override |
||||
protected Fragment getFragment() { |
||||
return new SelfCheckFragment(); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,34 @@
|
||||
package org.microg.nlp.app; |
||||
|
||||
import android.content.Intent; |
||||
import android.os.Bundle; |
||||
|
||||
import androidx.annotation.Nullable; |
||||
import androidx.appcompat.app.AppCompatActivity; |
||||
import androidx.navigation.NavController; |
||||
import androidx.navigation.fragment.NavHostFragment; |
||||
import androidx.navigation.ui.AppBarConfiguration; |
||||
import androidx.navigation.ui.NavigationUI; |
||||
|
||||
public class SettingsActivity extends AppCompatActivity { |
||||
private AppBarConfiguration appBarConfiguration; |
||||
|
||||
private NavController getNavController() { |
||||
return ((NavHostFragment)getSupportFragmentManager().findFragmentById(R.id.navhost)).getNavController(); |
||||
} |
||||
|
||||
@Override |
||||
protected void onCreate(@Nullable Bundle savedInstanceState) { |
||||
super.onCreate(savedInstanceState); |
||||
|
||||
setContentView(R.layout.settings_root_activity); |
||||
|
||||
appBarConfiguration = new AppBarConfiguration.Builder(getNavController().getGraph()).build(); |
||||
NavigationUI.setupActionBarWithNavController(this, getNavController(), appBarConfiguration); |
||||
} |
||||
|
||||
@Override |
||||
public boolean onSupportNavigateUp() { |
||||
return NavigationUI.navigateUp(getNavController(), appBarConfiguration) || super.onSupportNavigateUp(); |
||||
} |
||||
} |
@ -0,0 +1,112 @@
|
||||
/* |
||||
* 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. |
||||
*/ |
||||
|
||||
package org.microg.nlp.app.tools.selfcheck; |
||||
|
||||
import android.content.Context; |
||||
|
||||
import org.microg.nlp.app.R; |
||||
|
||||
import java.util.Arrays; |
||||
|
||||
import static android.os.Build.VERSION.SDK_INT; |
||||
import static android.os.Build.VERSION_CODES.JELLY_BEAN; |
||||
import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1; |
||||
import static android.os.Build.VERSION_CODES.KITKAT; |
||||
import static android.os.Build.VERSION_CODES.M; |
||||
|
||||
public class NlpOsCompatChecks implements SelfCheckGroup { |
||||
|
||||
public static final String CONFIG_NL_PROVIDER = "config_networkLocationProvider"; |
||||
public static final String CONFIG_NL_PROVIDER_PACKAGE_NAME = "config_networkLocationProviderPackageName"; |
||||
public static final String CONFIG_ENABLE_NL_OVERLAY = "config_enableNetworkLocationOverlay"; |
||||
public static final String CONFIG_NL_PROVIDER_PACKAGE_NAMES = "config_locationProviderPackageNames"; |
||||
|
||||
@Override |
||||
public String getGroupName(Context context) { |
||||
return context.getString(R.string.self_check_cat_nlpcompat); |
||||
} |
||||
|
||||
@Override |
||||
public void doChecks(Context context, ResultCollector collector) { |
||||
checkSystemIsSupported(context, collector); |
||||
checkSystemIsConfigured(context, collector); |
||||
} |
||||
|
||||
private boolean checkSystemIsSupported(Context context, ResultCollector collector) { |
||||
boolean isSupported = (SDK_INT >= KITKAT && SDK_INT <= M); |
||||
collector.addResult(context.getString(R.string.self_check_name_system_supported), |
||||
isSupported ? Result.Positive : Result.Unknown, context.getString(R.string.self_check_resolution_system_supported)); |
||||
return isSupported; |
||||
} |
||||
|
||||
private boolean checkSystemIsConfigured(Context context, ResultCollector collector) { |
||||
// 2.3+ com.android.internal.R.string.config_networkLocationProvider
|
||||
// 4.1+ com.android.internal.R.string.config_networkLocationProviderPackageName
|
||||
// 4.2+ com.android.internal.R.array.config_locationProviderPackageNames
|
||||
// 4.3+ com.android.internal.R.array.config_locationProviderPackageNames /
|
||||
// com.android.internal.R.string.config_networkLocationProviderPackageName /
|
||||
// com.android.internal.R.bool.config_enableNetworkLocationOverlay
|
||||
boolean systemMatchesPackage = false; |
||||
if (SDK_INT < JELLY_BEAN) { |
||||
systemMatchesPackage |= context.getPackageName().equals(getResourceString(context, CONFIG_NL_PROVIDER)); |
||||
} else { |
||||
boolean overlay = getResourceBool(context, CONFIG_ENABLE_NL_OVERLAY); |
||||
if (SDK_INT < JELLY_BEAN_MR1 || (SDK_INT > JELLY_BEAN_MR1 && !overlay)) { |
||||
systemMatchesPackage |= context.getPackageName().equals(getResourceString(context, CONFIG_NL_PROVIDER_PACKAGE_NAME)); |
||||
} |
||||
if (SDK_INT == JELLY_BEAN_MR1 || (SDK_INT > JELLY_BEAN_MR1 && overlay)) { |
||||
systemMatchesPackage |= Arrays.asList(getResourceArray(context, CONFIG_NL_PROVIDER_PACKAGE_NAMES)).contains(context.getPackageName()); |
||||
} |
||||
} |
||||
collector.addResult(context.getString(R.string.self_check_name_nlp_package_name), |
||||
systemMatchesPackage ? Result.Positive : Result.Negative, context.getString(R.string.self_check_resolution_nlp_package_name)); |
||||
return systemMatchesPackage; |
||||
} |
||||
|
||||
private String[] getResourceArray(Context context, String identifier) { |
||||
try { |
||||
int resId = context.getResources().getIdentifier(identifier, "array", "android"); |
||||
if (resId == 0) |
||||
resId = context.getResources().getIdentifier(identifier, "array", "com.android.internal"); |
||||
return context.getResources().getStringArray(resId); |
||||
} catch (Exception e) { |
||||
return new String[0]; |
||||
} |
||||
} |
||||
|
||||
private boolean getResourceBool(Context context, String identifier) { |
||||
try { |
||||
int resId = context.getResources().getIdentifier(identifier, "bool", "android"); |
||||
if (resId == 0) |
||||
resId = context.getResources().getIdentifier(identifier, "bool", "com.android.internal"); |
||||
return context.getResources().getBoolean(resId); |
||||
} catch (Exception e) { |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
private String getResourceString(Context context, String identifier) { |
||||
try { |
||||
int resId = context.getResources().getIdentifier(identifier, "string", "android"); |
||||
if (resId == 0) |
||||
resId = context.getResources().getIdentifier(identifier, "string", "com.android.internal"); |
||||
return context.getString(resId); |
||||
} catch (Exception e) { |
||||
return null; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,125 @@
|
||||
/* |
||||
* 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. |
||||
*/ |
||||
|
||||
package org.microg.nlp.app.tools.selfcheck; |
||||
|
||||
import android.content.Context; |
||||
import android.location.Location; |
||||
import android.location.LocationListener; |
||||
import android.location.LocationManager; |
||||
import android.os.Bundle; |
||||
import android.text.TextUtils; |
||||
|
||||
import org.microg.nlp.app.R; |
||||
import org.microg.nlp.client.UnifiedLocationClient; |
||||
|
||||
import java.util.concurrent.atomic.AtomicBoolean; |
||||
|
||||
import static android.content.Context.LOCATION_SERVICE; |
||||
import static android.location.LocationManager.NETWORK_PROVIDER; |
||||
import static org.microg.nlp.api.Constants.LOCATION_EXTRA_BACKEND_COMPONENT; |
||||
import static org.microg.nlp.app.tools.selfcheck.SelfCheckGroup.Result.Negative; |
||||
import static org.microg.nlp.app.tools.selfcheck.SelfCheckGroup.Result.Positive; |
||||
import static org.microg.nlp.app.tools.selfcheck.SelfCheckGroup.Result.Unknown; |
||||
|
||||
public class NlpStatusChecks implements SelfCheckGroup { |
||||
@Override |
||||
public String getGroupName(Context context) { |
||||
return context.getString(R.string.self_check_cat_nlp_status); |
||||
} |
||||
|
||||
@Override |
||||
public void doChecks(Context context, ResultCollector collector) { |
||||
providerWasBound(context, collector); |
||||
if (isNetworkLocationEnabled(context, collector)) { |
||||
isProvidingLastLocation(context, collector); |
||||
isProvidingLocation(context, collector); |
||||
} |
||||
} |
||||
|
||||
private boolean providerWasBound(Context context, ResultCollector collector) { |
||||
collector.addResult(context.getString(R.string.self_check_name_nlp_bound), |
||||
UnifiedLocationClient.get(context).isAvailable() ? Positive : Negative, context.getString(R.string.self_check_resolution_nlp_bound)); |
||||
return UnifiedLocationClient.get(context).isAvailable(); |
||||
} |
||||
|
||||
private boolean isNetworkLocationEnabled(Context context, ResultCollector collector) { |
||||
LocationManager locationManager = (LocationManager) context.getSystemService(LOCATION_SERVICE); |
||||
boolean networkEnabled = locationManager.getProviders(true).contains(NETWORK_PROVIDER); |
||||
collector.addResult(context.getString(R.string.self_check_name_network_enabled), |
||||
networkEnabled ? Positive : Negative, context.getString(R.string.self_check_resolution_network_enabled)); |
||||
return networkEnabled; |
||||
} |
||||
|
||||
private boolean isProvidingLastLocation(Context context, ResultCollector collector) { |
||||
LocationManager locationManager = (LocationManager) context.getSystemService(LOCATION_SERVICE); |
||||
try { |
||||
Location location = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER); |
||||
boolean hasKnown = location != null && location.getExtras() != null && |
||||
location.getExtras().containsKey(LOCATION_EXTRA_BACKEND_COMPONENT); |
||||
collector.addResult(context.getString(R.string.self_check_name_last_location), |
||||
hasKnown ? Positive : Unknown, context.getString(R.string.self_check_resolution_last_location)); |
||||
return hasKnown; |
||||
} catch (SecurityException e) { |
||||
collector.addResult(context.getString(R.string.self_check_name_last_location), Unknown, context.getString(R.string.self_check_loc_perm_missing)); |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
private void isProvidingLocation(final Context context, final ResultCollector collector) { |
||||
final AtomicBoolean result = new AtomicBoolean(false); |
||||
LocationManager locationManager = (LocationManager) context.getSystemService(LOCATION_SERVICE); |
||||
new Thread(new Runnable() { |
||||
@Override |
||||
public void run() { |
||||
synchronized (result) { |
||||
try { |
||||
result.wait(10000); |
||||
} catch (InterruptedException e) { |
||||
} |
||||
collector.addResult(context.getString(R.string.self_check_name_nlp_is_providing), |
||||
result.get() ? Positive : Unknown, context.getString(R.string.self_check_resolution_nlp_is_providing)); |
||||
} |
||||
} |
||||
}).start(); |
||||
try { |
||||
locationManager.requestSingleUpdate(NETWORK_PROVIDER, new LocationListener() { |
||||
@Override |
||||
public void onLocationChanged(Location location) { |
||||
synchronized (result) { |
||||
result.set(location != null && location.getExtras() != null && |
||||
location.getExtras().containsKey(LOCATION_EXTRA_BACKEND_COMPONENT)); |
||||
result.notifyAll(); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void onStatusChanged(String provider, int status, Bundle extras) { |
||||
} |
||||
|
||||
@Override |
||||
public void onProviderEnabled(String provider) { |
||||
} |
||||
|
||||
@Override |
||||
public void onProviderDisabled(String provider) { |
||||
} |
||||
}, null); |
||||
} catch (SecurityException e) { |
||||
collector.addResult(context.getString(R.string.self_check_name_last_location), Unknown, context.getString(R.string.self_check_loc_perm_missing)); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,69 @@
|
||||
/* |
||||
* 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.nlp.app.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.nlp.app.R; |
||||
|
||||
import static android.os.Build.VERSION_CODES.M; |
||||
import static org.microg.nlp.app.tools.selfcheck.SelfCheckGroup.Result.Negative; |
||||
import static org.microg.nlp.app.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); |
||||
CharSequence permLabel = info.loadLabel(pm); |
||||
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), |
||||
fragment -> fragment.requestPermissions(new String[]{permission}, 0)); |
||||
} catch (PackageManager.NameNotFoundException e) { |
||||
Log.w(TAG, e); |
||||
} |
||||
} |
||||
} |
@ -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.nlp.app.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 |
||||
} |
||||
} |
@ -0,0 +1,151 @@
|
||||
/* |
||||
* 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.nlp.app.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; |
||||
|
||||
import org.microg.nlp.app.R; |
||||
|
||||
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)); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,130 @@
|
||||
/* |
||||
* 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.nlp.app.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.nlp.app.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.nlp.app.tools.selfcheck.SelfCheckGroup.Result.Negative; |
||||
import static org.microg.nlp.app.tools.selfcheck.SelfCheckGroup.Result.Positive; |
||||
import static org.microg.nlp.app.tools.selfcheck.SelfCheckGroup.Result.Unknown; |
||||
|
||||
import org.microg.nlp.app.R; |
||||
|
||||
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); |
||||
} |
||||
}); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,78 @@
|
||||
package org.microg.nlp.app.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; |
||||
import org.microg.nlp.app.R; |
||||
|
||||
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; |
||||
} |
||||
} |
@ -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.nlp.app.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); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,116 @@
|
||||
/* |
||||
* 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.nlp.app.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; |
||||
|
||||
import org.microg.nlp.app.R; |
||||
|
||||
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; |
||||
} |
||||
} |
||||
} |
@ -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.nlp.app.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); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,266 @@
|
||||
/* |
||||
* 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.nlp.app.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; |
||||
import org.microg.nlp.app.R; |
||||
|
||||
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); |
||||