diff --git a/GNSSLogger/.idea/jarRepositories.xml b/GNSSLogger/.idea/jarRepositories.xml new file mode 100644 index 0000000..0a1b94d --- /dev/null +++ b/GNSSLogger/.idea/jarRepositories.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/GNSSLogger/app/build.gradle b/GNSSLogger/app/build.gradle index e2b770b..936cb46 100644 --- a/GNSSLogger/app/build.gradle +++ b/GNSSLogger/app/build.gradle @@ -2,6 +2,7 @@ plugins { id 'com.android.application' id 'com.google.android.libraries.mapsplatform.secrets-gradle-plugin' } +apply plugin: 'kotlin-android' android { compileSdk 32 @@ -26,6 +27,12 @@ android { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } + + testOptions { + unitTests { + includeAndroidResources = true + } + } } dependencies { @@ -38,8 +45,16 @@ dependencies { implementation files('libs/achartengine-1.2.0.jar') implementation("com.google.guava:guava:31.1-android") implementation 'com.google.android.material:material:1.6.1' + implementation "androidx.core:core:1.8.0" + testImplementation 'androidx.test:core:1.4.0' + testImplementation 'junit:junit:4.13.2' + testImplementation 'org.robolectric:robolectric:4.8.1' + testImplementation "com.google.truth:truth:1.1.3" androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' androidTestImplementation 'androidx.test.ext:junit:1.1.3' - testImplementation 'junit:junit:4.13.2' - implementation "androidx.core:core:1.8.0" + implementation "androidx.core:core-ktx:+" + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} +repositories { + mavenCentral() } \ No newline at end of file diff --git a/GNSSLogger/app/src/main/java/com/google/android/apps/location/gps/gnsslogger/MainActivity.java b/GNSSLogger/app/src/main/java/com/google/android/apps/location/gps/gnsslogger/MainActivity.java index f385309..5e7131a 100755 --- a/GNSSLogger/app/src/main/java/com/google/android/apps/location/gps/gnsslogger/MainActivity.java +++ b/GNSSLogger/app/src/main/java/com/google/android/apps/location/gps/gnsslogger/MainActivity.java @@ -16,7 +16,6 @@ package com.google.android.apps.location.gps.gnsslogger; - import android.Manifest; import android.app.Activity; import android.app.PendingIntent; @@ -42,6 +41,7 @@ import androidx.fragment.app.FragmentStatePagerAdapter; import androidx.localbroadcastmanager.content.LocalBroadcastManager; import androidx.viewpager.widget.ViewPager; +import com.google.android.apps.location.gps.gnsslogger.util.PendingIntentCompat; import com.google.android.gms.common.ConnectionResult; import com.google.android.gms.common.api.GoogleApiClient; import com.google.android.gms.common.api.GoogleApiClient.ConnectionCallbacks; @@ -141,12 +141,12 @@ protected void onCreate(Bundle savedInstanceState) { protected PendingIntent createActivityDetectionPendingIntent() { Intent intent = new Intent(this, DetectedActivitiesIntentReceiver.class); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { - return PendingIntent.getBroadcast(this, 0, intent, - PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE); - } else { - return PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); - } + return PendingIntentCompat.getBroadcast( + /* context= */ this, + /* requestCode= */ 0, + intent, + PendingIntent.FLAG_UPDATE_CURRENT, + /* isMutable= */ true); } private synchronized void buildGoogleApiClient() { diff --git a/GNSSLogger/app/src/main/java/com/google/android/apps/location/gps/gnsslogger/util/PendingIntentCompat.kt b/GNSSLogger/app/src/main/java/com/google/android/apps/location/gps/gnsslogger/util/PendingIntentCompat.kt new file mode 100644 index 0000000..b8da594 --- /dev/null +++ b/GNSSLogger/app/src/main/java/com/google/android/apps/location/gps/gnsslogger/util/PendingIntentCompat.kt @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2022 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.google.android.apps.location.gps.gnsslogger.util + +import android.content.Intent +import android.app.PendingIntent +import android.content.Context +import com.google.android.apps.location.gps.gnsslogger.util.PendingIntentCompat +import android.os.Build + +/** Helper for accessing features in [PendingIntent]. */ +object PendingIntentCompat { + /** + * Retrieves a [PendingIntent] with mandatory mutability flag set on supported platform + * versions. The caller provides the flag as combination of all the other values except mutability + * flag. This method combines mutability flag when necessary. See [ ][PendingIntent.getBroadcast]. + */ + @JvmStatic + fun getBroadcast( + context: Context, + requestCode: Int, + intent: Intent, + flags: Int, + isMutable: Boolean): PendingIntent { + return PendingIntent.getBroadcast( + context, requestCode, intent, addMutabilityFlags(isMutable, flags)) + } + + private fun addMutabilityFlags(isMutable: Boolean, flags: Int): Int { + var flags = flags + if (isMutable) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + flags = flags or PendingIntent.FLAG_MUTABLE + } + } else { + // Minimum support SDK is 24. + flags = flags or PendingIntent.FLAG_IMMUTABLE + } + return flags + } +} \ No newline at end of file diff --git a/GNSSLogger/app/src/test/java/com/google/android/apps/location/gps/gnsslogger/ExampleUnitTest.java b/GNSSLogger/app/src/test/java/com/google/android/apps/location/gps/gnsslogger/ExampleUnitTest.java deleted file mode 100644 index 00efbce..0000000 --- a/GNSSLogger/app/src/test/java/com/google/android/apps/location/gps/gnsslogger/ExampleUnitTest.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.google.android.apps.location.gps.gnsslogger; - -import static org.junit.Assert.*; - -import org.junit.Test; - -/** - * Example local unit test, which will execute on the development machine (host). - * - * @see Testing documentation - */ -public class ExampleUnitTest { - @Test - public void addition_isCorrect() { - assertEquals(4, 2 + 2); - } -} diff --git a/GNSSLogger/app/src/test/java/com/google/android/apps/location/gps/gnsslogger/util/PendingIntentCompatTest.java b/GNSSLogger/app/src/test/java/com/google/android/apps/location/gps/gnsslogger/util/PendingIntentCompatTest.java new file mode 100644 index 0000000..f44d1d2 --- /dev/null +++ b/GNSSLogger/app/src/test/java/com/google/android/apps/location/gps/gnsslogger/util/PendingIntentCompatTest.java @@ -0,0 +1,121 @@ +package com.google.android.apps.location.gps.gnsslogger.util; + +import static com.google.common.truth.Truth.assertThat; +import static org.robolectric.Shadows.shadowOf; + +import android.app.PendingIntent; +import android.content.Context; +import android.content.Intent; +import android.os.Build; +import androidx.test.core.app.ApplicationProvider; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.annotation.Config; +import org.robolectric.shadows.ShadowPendingIntent; + +/** Unit test for {@link PendingIntentCompat}. */ +@RunWith(RobolectricTestRunner.class) +public class PendingIntentCompatTest { + private final Context context = ApplicationProvider.getApplicationContext(); + + /** Immutable is introduced in M, but the project's minimum support version is 24 */ + @Config(sdk = Build.VERSION_CODES.N) + @Test + public void addMutabilityFlags_immutableOnMPlus() { + int requestCode = 7465; + Intent intent = new Intent(); + ShadowPendingIntent shadow = + shadowOf( + PendingIntentCompat.getBroadcast( + context, + requestCode, + intent, + PendingIntent.FLAG_UPDATE_CURRENT, + /* isMutable= */ false)); + assertThat(shadow.getFlags()) + .isEqualTo(PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE); + } + + @Config(maxSdk = Build.VERSION_CODES.R) + @Test + public void addMutabilityFlags_mutableOnPreS() { + int requestCode = 7465; + Intent intent = new Intent(); + ShadowPendingIntent shadow = + shadowOf( + PendingIntentCompat.getBroadcast( + context, + requestCode, + intent, + PendingIntent.FLAG_UPDATE_CURRENT, + /* isMutable= */ true)); + assertThat(shadow.getFlags()).isEqualTo(PendingIntent.FLAG_UPDATE_CURRENT); + } + + @Config(maxSdk = Build.VERSION_CODES.R) + @Test + public void addMutabilityFlags_immutableOnPreS() { + int requestCode = 7465; + Intent intent = new Intent(); + ShadowPendingIntent shadow = + shadowOf( + PendingIntentCompat.getBroadcast( + context, + requestCode, + intent, + PendingIntent.FLAG_UPDATE_CURRENT, + /* isMutable= */ false)); + assertThat(shadow.getFlags()) + .isEqualTo(PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE); + } + + @Config(minSdk = Build.VERSION_CODES.S) + @Test + public void addMutabilityFlags_mutableOnSPlus() { + int requestCode = 7465; + Intent intent = new Intent(); + ShadowPendingIntent shadow = + shadowOf( + PendingIntentCompat.getBroadcast( + context, + requestCode, + intent, + PendingIntent.FLAG_UPDATE_CURRENT, + /* isMutable= */ true)); + assertThat(shadow.getFlags()) + .isEqualTo(PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE); + } + + @Config(minSdk = Build.VERSION_CODES.S) + @Test + public void addMutabilityFlags_immutableOnSPlus() { + int requestCode = 7465; + Intent intent = new Intent(); + ShadowPendingIntent shadow = + shadowOf( + PendingIntentCompat.getBroadcast( + context, + requestCode, + intent, + PendingIntent.FLAG_UPDATE_CURRENT, + /* isMutable= */ false)); + assertThat(shadow.getFlags()) + .isEqualTo(PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE); + } + + @Test + public void getBroadcast() { + int requestCode = 7465; + Intent intent = new Intent(); + ShadowPendingIntent shadow = + shadowOf( + PendingIntentCompat.getBroadcast( + context, + requestCode, + intent, + PendingIntent.FLAG_UPDATE_CURRENT, + /* isMutable= */ false)); + assertThat(shadow.isBroadcast()).isTrue(); + } +} diff --git a/GNSSLogger/build.gradle b/GNSSLogger/build.gradle index 41052eb..bb78f47 100644 --- a/GNSSLogger/build.gradle +++ b/GNSSLogger/build.gradle @@ -1,4 +1,13 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. +buildscript { + ext.kotlin_version = '1.7.20-Beta' + repositories { + mavenCentral() + } + dependencies { + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} plugins { id 'com.android.application' version '7.2.1' apply false id 'com.android.library' version '7.2.1' apply false diff --git a/GNSSLogger/settings.gradle b/GNSSLogger/settings.gradle index 0e73733..58d7621 100644 --- a/GNSSLogger/settings.gradle +++ b/GNSSLogger/settings.gradle @@ -6,7 +6,7 @@ pluginManagement { } } dependencyResolutionManagement { - repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) + repositoriesMode.set(RepositoriesMode.PREFER_SETTINGS) repositories { google() mavenCentral()