diff options
23 files changed, 566 insertions, 0 deletions
diff --git a/Android.mk b/Android.mk new file mode 100644 index 0000000..d2e2a8d --- /dev/null +++ b/Android.mk @@ -0,0 +1,25 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_USE_AAPT2 := true + +LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res + +LOCAL_STATIC_ANDROID_LIBRARIES := \ + androidx.core_core \ + androidx.appcompat_appcompat + +# Build all java files in the src subdirectory +LOCAL_SRC_FILES := $(call all-java-files-under, src) + +LOCAL_SDK_VERSION := current + +LOCAL_PRIVILEGED_MODULE := true +LOCAL_PRODUCT_MODULE := true + +# Name of the APK to build +LOCAL_PACKAGE_NAME := SampleLocationAttribution + +# Tell it to build an APK +include $(BUILD_PACKAGE) diff --git a/AndroidManifest.xml b/AndroidManifest.xml new file mode 100644 index 0000000..04029ca --- /dev/null +++ b/AndroidManifest.xml @@ -0,0 +1,46 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright 2019 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. +--> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.example.android.locationattribution"> + + <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> + <!-- Requires permission "Allow all the time" and not just "Allow only while the app is in use" --> + <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" /> + + <application + android:allowBackup="true" + android:icon="@mipmap/ic_launcher" + android:label="@string/app_name" + android:roundIcon="@mipmap/ic_launcher_round" + android:supportsRtl="true" + android:theme="@style/AppTheme"> + <activity android:name=".MainActivity"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + <intent-filter> + <action android:name="android.intent.action.APPLICATION_PREFERENCES" /> + <category android:name="android.intent.category.DEFAULT" /> + </intent-filter> + <intent-filter> + <action android:name="com.example.android.locationattribution.intent.action.NON_FRAMEWORK_LOCATION" /> + <category android:name="android.intent.category.DEFAULT" /> + </intent-filter> + </activity> + </application> +</manifest> @@ -0,0 +1,4 @@ +aadmal@google.com +gomo@google.com +wyattriley@google.com +yuhany@google.com diff --git a/res/drawable-v24/ic_launcher_foreground.xml b/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 0000000..1f6bb29 --- /dev/null +++ b/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,34 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:aapt="http://schemas.android.com/aapt" + android:width="108dp" + android:height="108dp" + android:viewportWidth="108" + android:viewportHeight="108"> + <path + android:fillType="evenOdd" + android:pathData="M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z" + android:strokeWidth="1" + android:strokeColor="#00000000"> + <aapt:attr name="android:fillColor"> + <gradient + android:endX="78.5885" + android:endY="90.9159" + android:startX="48.7653" + android:startY="61.0927" + android:type="linear"> + <item + android:color="#44000000" + android:offset="0.0" /> + <item + android:color="#00000000" + android:offset="1.0" /> + </gradient> + </aapt:attr> + </path> + <path + android:fillColor="#FFFFFF" + android:fillType="nonZero" + android:pathData="M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z" + android:strokeWidth="1" + android:strokeColor="#00000000" /> +</vector> diff --git a/res/drawable/button_modify_location_settings_shape.xml b/res/drawable/button_modify_location_settings_shape.xml new file mode 100644 index 0000000..e321c5d --- /dev/null +++ b/res/drawable/button_modify_location_settings_shape.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8"?> +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle"> + <solid android:color="@color/google_blue600" /> + <corners android:radius="7dp" /> +</shape>
\ No newline at end of file diff --git a/res/drawable/ic_launcher_background.xml b/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..0d025f9 --- /dev/null +++ b/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ +<?xml version="1.0" encoding="utf-8"?> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="108dp" + android:height="108dp" + android:viewportWidth="108" + android:viewportHeight="108"> + <path + android:fillColor="#008577" + android:pathData="M0,0h108v108h-108z" /> + <path + android:fillColor="#00000000" + android:pathData="M9,0L9,108" + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + <path + android:fillColor="#00000000" + android:pathData="M19,0L19,108" + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + <path + android:fillColor="#00000000" + android:pathData="M29,0L29,108" + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + <path + android:fillColor="#00000000" + android:pathData="M39,0L39,108" + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + <path + android:fillColor="#00000000" + android:pathData="M49,0L49,108" + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + <path + android:fillColor="#00000000" + android:pathData="M59,0L59,108" + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + <path + android:fillColor="#00000000" + android:pathData="M69,0L69,108" + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + <path + android:fillColor="#00000000" + android:pathData="M79,0L79,108" + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + <path + android:fillColor="#00000000" + android:pathData="M89,0L89,108" + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + <path + android:fillColor="#00000000" + android:pathData="M99,0L99,108" + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + <path + android:fillColor="#00000000" + android:pathData="M0,9L108,9" + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + <path + android:fillColor="#00000000" + android:pathData="M0,19L108,19" + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + <path + android:fillColor="#00000000" + android:pathData="M0,29L108,29" + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + <path + android:fillColor="#00000000" + android:pathData="M0,39L108,39" + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + <path + android:fillColor="#00000000" + android:pathData="M0,49L108,49" + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + <path + android:fillColor="#00000000" + android:pathData="M0,59L108,59" + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + <path + android:fillColor="#00000000" + android:pathData="M0,69L108,69" + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + <path + android:fillColor="#00000000" + android:pathData="M0,79L108,79" + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + <path + android:fillColor="#00000000" + android:pathData="M0,89L108,89" + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + <path + android:fillColor="#00000000" + android:pathData="M0,99L108,99" + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + <path + android:fillColor="#00000000" + android:pathData="M19,29L89,29" + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + <path + android:fillColor="#00000000" + android:pathData="M19,39L89,39" + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + <path + android:fillColor="#00000000" + android:pathData="M19,49L89,49" + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + <path + android:fillColor="#00000000" + android:pathData="M19,59L89,59" + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + <path + android:fillColor="#00000000" + android:pathData="M19,69L89,69" + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + <path + android:fillColor="#00000000" + android:pathData="M19,79L89,79" + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + <path + android:fillColor="#00000000" + android:pathData="M29,19L29,89" + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + <path + android:fillColor="#00000000" + android:pathData="M39,19L39,89" + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + <path + android:fillColor="#00000000" + android:pathData="M49,19L49,89" + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + <path + android:fillColor="#00000000" + android:pathData="M59,19L59,89" + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + <path + android:fillColor="#00000000" + android:pathData="M69,19L69,89" + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> + <path + android:fillColor="#00000000" + android:pathData="M79,19L79,89" + android:strokeWidth="0.8" + android:strokeColor="#33FFFFFF" /> +</vector> diff --git a/res/layout/activity_main.xml b/res/layout/activity_main.xml new file mode 100644 index 0000000..55f3d12 --- /dev/null +++ b/res/layout/activity_main.xml @@ -0,0 +1,42 @@ +<?xml version="1.0" encoding="utf-8"?> +<ScrollView xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:scrollbarStyle="outsideOverlay" > + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical" + android:layout_gravity="center_horizontal" + android:gravity="center_horizontal" > + + <TextView + android:id="@+id/textViewAppInfo" + android:layout_width="321dp" + android:layout_height="wrap_content" + android:layout_marginStart="8dp" + android:layout_marginEnd="8dp" + android:layout_marginTop="24dp" + android:layout_gravity="center" + android:textColorLink="@color/google_blue600" + android:text="@string/textViewAppInfo" + android:textSize="16sp" + android:textAppearance="@android:style/TextAppearance" /> + + <Button + android:id="@+id/buttonModifyLocationSettings" + style="@android:style/Widget.DeviceDefault.Button.Borderless" + android:layout_width="264dp" + android:layout_height="wrap_content" + android:layout_marginStart="8dp" + android:layout_marginEnd="8dp" + android:layout_marginTop="16dp" + android:layout_marginBottom="48dp" + android:gravity="center_vertical|center_horizontal" + android:background="@drawable/button_modify_location_settings_shape" + android:text="@string/buttonModifyLocationSettings" + android:textAllCaps="false" + android:textColor="@android:color/white"/> + </LinearLayout> +</ScrollView>
\ No newline at end of file diff --git a/res/mipmap-anydpi-v26/ic_launcher.xml b/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 0000000..eca70cf --- /dev/null +++ b/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"> + <background android:drawable="@drawable/ic_launcher_background" /> + <foreground android:drawable="@drawable/ic_launcher_foreground" /> +</adaptive-icon>
\ No newline at end of file diff --git a/res/mipmap-anydpi-v26/ic_launcher_round.xml b/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 0000000..eca70cf --- /dev/null +++ b/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"> + <background android:drawable="@drawable/ic_launcher_background" /> + <foreground android:drawable="@drawable/ic_launcher_foreground" /> +</adaptive-icon>
\ No newline at end of file diff --git a/res/mipmap-hdpi/ic_launcher.png b/res/mipmap-hdpi/ic_launcher.png Binary files differnew file mode 100644 index 0000000..898f3ed --- /dev/null +++ b/res/mipmap-hdpi/ic_launcher.png diff --git a/res/mipmap-hdpi/ic_launcher_round.png b/res/mipmap-hdpi/ic_launcher_round.png Binary files differnew file mode 100644 index 0000000..dffca36 --- /dev/null +++ b/res/mipmap-hdpi/ic_launcher_round.png diff --git a/res/mipmap-mdpi/ic_launcher.png b/res/mipmap-mdpi/ic_launcher.png Binary files differnew file mode 100644 index 0000000..64ba76f --- /dev/null +++ b/res/mipmap-mdpi/ic_launcher.png diff --git a/res/mipmap-mdpi/ic_launcher_round.png b/res/mipmap-mdpi/ic_launcher_round.png Binary files differnew file mode 100644 index 0000000..dae5e08 --- /dev/null +++ b/res/mipmap-mdpi/ic_launcher_round.png diff --git a/res/mipmap-xhdpi/ic_launcher.png b/res/mipmap-xhdpi/ic_launcher.png Binary files differnew file mode 100644 index 0000000..e5ed465 --- /dev/null +++ b/res/mipmap-xhdpi/ic_launcher.png diff --git a/res/mipmap-xhdpi/ic_launcher_round.png b/res/mipmap-xhdpi/ic_launcher_round.png Binary files differnew file mode 100644 index 0000000..14ed0af --- /dev/null +++ b/res/mipmap-xhdpi/ic_launcher_round.png diff --git a/res/mipmap-xxhdpi/ic_launcher.png b/res/mipmap-xxhdpi/ic_launcher.png Binary files differnew file mode 100644 index 0000000..b0907ca --- /dev/null +++ b/res/mipmap-xxhdpi/ic_launcher.png diff --git a/res/mipmap-xxhdpi/ic_launcher_round.png b/res/mipmap-xxhdpi/ic_launcher_round.png Binary files differnew file mode 100644 index 0000000..d8ae031 --- /dev/null +++ b/res/mipmap-xxhdpi/ic_launcher_round.png diff --git a/res/mipmap-xxxhdpi/ic_launcher.png b/res/mipmap-xxxhdpi/ic_launcher.png Binary files differnew file mode 100644 index 0000000..2c18de9 --- /dev/null +++ b/res/mipmap-xxxhdpi/ic_launcher.png diff --git a/res/mipmap-xxxhdpi/ic_launcher_round.png b/res/mipmap-xxxhdpi/ic_launcher_round.png Binary files differnew file mode 100644 index 0000000..beed3cd --- /dev/null +++ b/res/mipmap-xxxhdpi/ic_launcher_round.png diff --git a/res/values/colors.xml b/res/values/colors.xml new file mode 100644 index 0000000..d0b29e5 --- /dev/null +++ b/res/values/colors.xml @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <color name="colorPrimary">#008577</color> + <color name="colorPrimaryDark">#00574B</color> + <color name="colorAccent">#D81B60</color> + <color name="colorBlack">#000000</color> + <color name="google_blue600">#1a73e8</color> +</resources> diff --git a/res/values/strings.xml b/res/values/strings.xml new file mode 100644 index 0000000..f4b3404 --- /dev/null +++ b/res/values/strings.xml @@ -0,0 +1,19 @@ +<resources> + <string name="app_name">Sample Location Attribution</string> + <string name="textViewAppInfo"></string> + <!-- + - The main screen (and the only one for this app) displays the text to the user regarding + - device's location access by Non-Android entities outside the Android framework control. + - Each string-array item denotes a separate paragraph. + --> + <string-array name="textViewAppInfo_Paragraphs"> + <item>REPLACE THE TEXT BELOW WITH YOUR OWN TEXT EXPLAINING YOUR NON-ANDROID LOCATION ACCESS USE CASE(S).\n\n</item> + <item>This service ...\n</item> + <item><explain what your service does here ... >\n\n</item> + <item>To allow this service to access your device GPS location, enable location permission at the "Allow all the time" level.\n\n</item> + <item><a href="location_attribution_app://learn_more">Learn more</a>\n</item> + </string-array> + <!-- NOTE: Replace this link with the actual link to your Non-Android service's help web page --> + <string name="urlLearnMore" translatable="false">https://support.oem-name-here.com/path/doc</string> + <string name="buttonModifyLocationSettings">Modify app location permission</string> +</resources>
\ No newline at end of file diff --git a/res/values/styles.xml b/res/values/styles.xml new file mode 100644 index 0000000..5885930 --- /dev/null +++ b/res/values/styles.xml @@ -0,0 +1,11 @@ +<resources> + + <!-- Base application theme. --> + <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"> + <!-- Customize your theme here. --> + <item name="colorPrimary">@color/colorPrimary</item> + <item name="colorPrimaryDark">@color/colorPrimaryDark</item> + <item name="colorAccent">@color/colorAccent</item> + </style> + +</resources> diff --git a/src/com/example/android/locationattribution/MainActivity.java b/src/com/example/android/locationattribution/MainActivity.java new file mode 100644 index 0000000..1ca5c35 --- /dev/null +++ b/src/com/example/android/locationattribution/MainActivity.java @@ -0,0 +1,191 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.android.locationattribution; + +import android.Manifest; +import android.content.Intent; +import android.content.SharedPreferences; +import android.content.pm.PackageManager; +import android.net.Uri; +import androidx.core.app.ActivityCompat; +import androidx.core.content.ContextCompat; +import androidx.appcompat.app.AppCompatActivity; +import android.os.Bundle; +import android.text.Spannable; +import android.text.SpannableStringBuilder; +import android.text.TextPaint; +import android.text.method.LinkMovementMethod; +import android.text.style.ClickableSpan; +import android.text.style.URLSpan; +import android.util.Log; +import android.view.View; +import android.widget.Button; +import android.widget.TextView; + +/** + * Non-framework Location Attribution sample application. + * + * <p>This location attribution sample application demonstrates how to give user visibility + * and control of non-user-emergency location access by non-framework entities accessing GNSS + * chipset API directly bypassing the standard Android framework location permission settings. + * + * <p>Displays text to the user about the benefits of giving location permission to this app so + * that the non-framework entity or entities this app represents can access device location from + * GNSS chipset directly. + * + * <p>Provides a button to allow the user to modify the location permission settings for this app. + */ +public class MainActivity extends AppCompatActivity { + private static final String APPLICATION_ID = "com.example.android.locationattribution"; + private static final String TAG = "LocationAttribution"; + private static final String PREFS_FILE_NAME = "LocationAttributionPrefs"; + private static final int NON_FRAMEWORK_LOCATION_PERMISSION = 100; + + private static final String URL_PREFIX = "location_attribution_app://"; + private static final String LINK_LEARN_MORE = URL_PREFIX + "learn_more"; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + // Set non-framework location access use case description to display. + setTextViewAppInfoContent(); + + // Show button for the user to modify location settings for this app. + Button button = (Button)findViewById(R.id.buttonModifyLocationSettings); + button.setOnClickListener(createModifyLocationSettingsButtonClickListener()); + } + + private void setTextViewAppInfoContent() { + // This text is seen by the user when this app is opened through the App info screen in + // Android Settings or when an intent is sent by carrier's own app. + TextView textViewAppInfo = findViewById(R.id.textViewAppInfo); + SpannableStringBuilder textViewAppInfoText = new SpannableStringBuilder(); + for (CharSequence paragraph : getResources().getTextArray( + R.array.textViewAppInfo_Paragraphs)) { + textViewAppInfoText.append(paragraph); + } + + replaceUrlSpansWithClickableSpans(textViewAppInfoText); + textViewAppInfo.setText(textViewAppInfoText); + textViewAppInfo.setMovementMethod(LinkMovementMethod.getInstance()); + } + + private View.OnClickListener createModifyLocationSettingsButtonClickListener() { + return new View.OnClickListener() { + @Override + public void onClick(View v) { + if (ContextCompat.checkSelfPermission(MainActivity.this, + Manifest.permission.ACCESS_FINE_LOCATION) + == PackageManager.PERMISSION_GRANTED) { + // We can't show tri-state dialog when permission is already granted. + // So, go to the location permission settings screen directly. + showLocationPermissionSettingsDashboard(); + return; + } + + if (isFirstTimeAskingLocationPermission()) { + // Show tri-state dialog to change permission. + setFirstTimeAskingLocationPermission(false); + showRequestLocationPermissionDialog(); + return; + } + + if (ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this, + Manifest.permission.ACCESS_FINE_LOCATION)) { + // The user has previously denied the request. Show the tri-state dialog again. + showRequestLocationPermissionDialog(); + } else { + // User has denied permission and selected 'Don't ask again' option. + showLocationPermissionSettingsDashboard(); + } + } + }; + } + + private void showRequestLocationPermissionDialog() { + ActivityCompat.requestPermissions(this, + new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, + NON_FRAMEWORK_LOCATION_PERMISSION); + } + + private void showLocationPermissionSettingsDashboard() { + startActivity(new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS, + Uri.parse("package:" + APPLICATION_ID))); + } + + private void setFirstTimeAskingLocationPermission(boolean isFirstTime) { + SharedPreferences sharedPreference = getApplicationContext().getSharedPreferences( + PREFS_FILE_NAME, MODE_PRIVATE); + SharedPreferences.Editor editor = sharedPreference.edit(); + editor.putBoolean(Manifest.permission.ACCESS_FINE_LOCATION, isFirstTime).apply(); + editor.commit(); + } + + private boolean isFirstTimeAskingLocationPermission() { + return getApplicationContext().getSharedPreferences(PREFS_FILE_NAME, + MODE_PRIVATE).getBoolean(Manifest.permission.ACCESS_FINE_LOCATION, true); + } + + /** + * A clickable text listener. + * + * <p>Used to listen to click events for clickable text in the description displayed by this + * activity's main screen and navigate to the appropriate screen based on the text link + * clicked. + */ + private class AppInfoTextLinkClickableSpan extends ClickableSpan { + private final String mUrl; + + private AppInfoTextLinkClickableSpan(String url) { + mUrl = url; + } + + @Override + public void onClick(View textView) { + switch (mUrl) { + case LINK_LEARN_MORE: + startActivity(new Intent(Intent.ACTION_VIEW, + Uri.parse(getString(R.string.urlLearnMore)))); + break; + default: + Log.e(TAG, "@string/textViewAppInfo contains invalid URL: " + mUrl); + } + } + + @Override + public void updateDrawState(TextPaint drawState) { + super.updateDrawState(drawState); + drawState.setUnderlineText(false); + } + } + + /* + * The description text in {@code textAppInfo} shown in the activity screen has URL links. + * Replace those links with clickable links so that we get notified when those links are + * clicked. We can then navigate to different screens based on the links clicked. + */ + private void replaceUrlSpansWithClickableSpans(Spannable textAppInfo) { + for(URLSpan span: textAppInfo.getSpans(0, textAppInfo.length(), URLSpan.class)) { + int start = textAppInfo.getSpanStart(span); + int end = textAppInfo.getSpanEnd(span); + textAppInfo.removeSpan(span); + textAppInfo.setSpan(new AppInfoTextLinkClickableSpan(span.getURL()), start, end, 0); + } + } +} |