From d8d44c3b5989a2aa5174da4a99b9dade1a91f4fb Mon Sep 17 00:00:00 2001 From: M66B Date: Fri, 9 Jun 2023 16:56:08 +0200 Subject: [PATCH] Updated Android car --- app/build.gradle | 2 +- .../car/app/connection/CarConnection.java | 194 +++++++++--------- .../connection/CarConnectionTypeLiveData.java | 41 +++- 3 files changed, 130 insertions(+), 107 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index b34ef081ff..e0d18ce26a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -711,7 +711,7 @@ dependencies { implementation "com.github.seancfoley:ipaddress:$ipaddress_version" // https://mvnrepository.com/artifact/androidx.car.app/app?repo=google - // implementation "androidx.car.app:app:1.2.0-rc01" + // implementation "androidx.car.app:app:1.4.0-alpha01" // https://github.com/square/leakcanary // https://square.github.io/leakcanary/getting_started/ diff --git a/app/src/main/java/androidx/car/app/connection/CarConnection.java b/app/src/main/java/androidx/car/app/connection/CarConnection.java index 06c4691182..002aec984e 100644 --- a/app/src/main/java/androidx/car/app/connection/CarConnection.java +++ b/app/src/main/java/androidx/car/app/connection/CarConnection.java @@ -1,112 +1,112 @@ - /* - * Copyright 2021 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. - */ +/* + * Copyright 2021 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 androidx.car.app.connection; +package androidx.car.app.connection; - import static androidx.annotation.RestrictTo.Scope.LIBRARY; - //import static androidx.car.app.utils.CommonUtils.isAutomotiveOS; +import static androidx.annotation.RestrictTo.Scope.LIBRARY; +//import static androidx.car.app.utils.CommonUtils.isAutomotiveOS; - import static java.util.Objects.requireNonNull; +import static java.util.Objects.requireNonNull; - import android.content.Context; +import android.content.Context; - import androidx.annotation.IntDef; - import androidx.annotation.NonNull; - import androidx.annotation.RestrictTo; - import androidx.lifecycle.LiveData; +import androidx.annotation.IntDef; +import androidx.annotation.MainThread; +import androidx.annotation.NonNull; +import androidx.annotation.RestrictTo; +import androidx.lifecycle.LiveData; - import java.lang.annotation.ElementType; - import java.lang.annotation.Retention; - import java.lang.annotation.RetentionPolicy; - import java.lang.annotation.Target; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; - /** - * A class that allows retrieval of information about connection to a car head unit. - */ - public final class CarConnection { - /** - * Defines current car connection state. - * - *

This is used for communication with the car host's content provider on queries for - * connection type. - */ - public static final String CAR_CONNECTION_STATE = "CarConnectionState"; +/** + * A class that allows retrieval of information about connection to a car head unit. + */ +public final class CarConnection { + /** + * Defines current car connection state. + * + *

This is used for communication with the car host's content provider on queries for + * connection type. + */ + public static final String CAR_CONNECTION_STATE = "CarConnectionState"; - /** - * Broadcast action that notifies that the car connection has changed and needs to be updated. - */ - public static final String ACTION_CAR_CONNECTION_UPDATED = - "androidx.car.app.connection.action.CAR_CONNECTION_UPDATED"; + /** + * Broadcast action that notifies that the car connection has changed and needs to be updated. + */ + public static final String ACTION_CAR_CONNECTION_UPDATED = + "androidx.car.app.connection.action.CAR_CONNECTION_UPDATED"; - /** - * Represents the types of connections that exist to a car head unit. - * - * @hide - */ - @IntDef({CONNECTION_TYPE_NOT_CONNECTED, CONNECTION_TYPE_NATIVE, CONNECTION_TYPE_PROJECTION}) - @Retention(RetentionPolicy.SOURCE) - @Target({ElementType.TYPE_USE}) - @RestrictTo(LIBRARY) - public @interface ConnectionType { - } + /** + * Represents the types of connections that exist to a car head unit. + * + * @hide + */ + @IntDef({CONNECTION_TYPE_NOT_CONNECTED, CONNECTION_TYPE_NATIVE, CONNECTION_TYPE_PROJECTION}) + @Retention(RetentionPolicy.SOURCE) + @Target({ElementType.TYPE_USE}) + @RestrictTo(LIBRARY) + public @interface ConnectionType { + } - /** - * Not connected to any car head unit.z - */ - public static final int CONNECTION_TYPE_NOT_CONNECTED = 0; + /** + * Not connected to any car head unit.z + */ + public static final int CONNECTION_TYPE_NOT_CONNECTED = 0; - /** - * Natively running on a head unit (Android Automotive OS). - */ - public static final int CONNECTION_TYPE_NATIVE = 1; + /** + * Natively running on a head unit (Android Automotive OS). + */ + public static final int CONNECTION_TYPE_NATIVE = 1; - /** - * Connected to a car head unit by projecting to it. - */ - public static final int CONNECTION_TYPE_PROJECTION = 2; + /** + * Connected to a car head unit by projecting to it. + */ + public static final int CONNECTION_TYPE_PROJECTION = 2; - private final LiveData mConnectionTypeLiveData; + private final LiveData mConnectionTypeLiveData; - /** - * Constructs a {@link CarConnection} that can be used to get connection information. - * - * @throws NullPointerException if {@code context} is {@code null} - */ - public CarConnection(@NonNull Context context) { - requireNonNull(context); - mConnectionTypeLiveData = /*isAutomotiveOS(context) - ? new AutomotiveCarConnectionTypeLiveData() - :*/ new CarConnectionTypeLiveData(context); - } + /** + * Constructs a {@link CarConnection} that can be used to get connection information. + * + * @throws NullPointerException if {@code context} is {@code null} + */ + @MainThread + public CarConnection(@NonNull Context context) { + requireNonNull(context); + mConnectionTypeLiveData = new CarConnectionTypeLiveData(context); + } - /** - * Returns a {@link LiveData} that can be observed to get current connection type. - * - *

The recommended pattern is to observe the {@link LiveData} with the activity's - * lifecycle in order to get updates on the state change throughout the activity's lifetime. - * - *

Connection types are: - *

    - *
  1. {@link #CONNECTION_TYPE_NOT_CONNECTED} - *
  2. {@link #CONNECTION_TYPE_NATIVE} - *
  3. {@link #CONNECTION_TYPE_PROJECTION} - *
- */ - @NonNull - public LiveData<@ConnectionType Integer> getType() { - return mConnectionTypeLiveData; - } - } + /** + * Returns a {@link LiveData} that can be observed to get current connection type. + * + *

The recommended pattern is to observe the {@link LiveData} with the activity's + * lifecycle in order to get updates on the state change throughout the activity's lifetime. + * + *

Connection types are: + *

    + *
  1. {@link #CONNECTION_TYPE_NOT_CONNECTED} + *
  2. {@link #CONNECTION_TYPE_NATIVE} + *
  3. {@link #CONNECTION_TYPE_PROJECTION} + *
+ */ + @NonNull + public LiveData<@ConnectionType Integer> getType() { + return mConnectionTypeLiveData; + } +} diff --git a/app/src/main/java/androidx/car/app/connection/CarConnectionTypeLiveData.java b/app/src/main/java/androidx/car/app/connection/CarConnectionTypeLiveData.java index e688eb2d22..f8f6a3cfda 100644 --- a/app/src/main/java/androidx/car/app/connection/CarConnectionTypeLiveData.java +++ b/app/src/main/java/androidx/car/app/connection/CarConnectionTypeLiveData.java @@ -18,7 +18,7 @@ package androidx.car.app.connection; import static androidx.car.app.connection.CarConnection.ACTION_CAR_CONNECTION_UPDATED; import static androidx.car.app.connection.CarConnection.CAR_CONNECTION_STATE; -//import static androidx.car.app.utils.LogTags.TAG_CONNECTION_TO_CAR; +import static androidx.car.app.utils.LogTags.TAG_CONNECTION_TO_CAR; import android.content.AsyncQueryHandler; import android.content.BroadcastReceiver; @@ -28,8 +28,11 @@ import android.content.Intent; import android.content.IntentFilter; import android.database.Cursor; import android.net.Uri; +import android.os.Build; import android.util.Log; +import androidx.annotation.DoNotInline; +import androidx.annotation.RequiresApi; import androidx.annotation.VisibleForTesting; import androidx.car.app.connection.CarConnection.ConnectionType; import androidx.lifecycle.LiveData; @@ -60,8 +63,15 @@ final class CarConnectionTypeLiveData extends LiveData<@ConnectionType Integer> @Override public void onActive() { - mContext.registerReceiver(mBroadcastReceiver, - new IntentFilter(ACTION_CAR_CONNECTION_UPDATED)); + // TODO(b/240576633): Replace this entire if-block with a call to + // ContextCompat#registerReceiver once it's released in androidx.core + IntentFilter filter = new IntentFilter(ACTION_CAR_CONNECTION_UPDATED); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + Api33Impl.registerExportedReceiver(mContext, mBroadcastReceiver, filter); + } else { + mContext.registerReceiver(mBroadcastReceiver, filter); + } + queryForState(); } @@ -86,23 +96,23 @@ final class CarConnectionTypeLiveData extends LiveData<@ConnectionType Integer> @Override protected void onQueryComplete(int token, Object cookie, Cursor response) { if (response == null) { - //Log.w(TAG_CONNECTION_TO_CAR, "Null response from content provider when checking " - // + "connection to the car, treating as disconnected"); + Log.w(TAG_CONNECTION_TO_CAR, "Null response from content provider when checking " + + "connection to the car, treating as disconnected"); postValue(CarConnection.CONNECTION_TYPE_NOT_CONNECTED); return; } int carConnectionTypeColumn = response.getColumnIndex(CAR_CONNECTION_STATE); if (carConnectionTypeColumn < 0) { - //Log.e(TAG_CONNECTION_TO_CAR, "Connection to car response is missing the " - // + "connection type, treating as disconnected"); + Log.e(TAG_CONNECTION_TO_CAR, "Connection to car response is missing the " + + "connection type, treating as disconnected"); postValue(CarConnection.CONNECTION_TYPE_NOT_CONNECTED); return; } if (!response.moveToNext()) { - //Log.e(TAG_CONNECTION_TO_CAR, "Connection to car response is empty, treating as " - // + "disconnected"); + Log.e(TAG_CONNECTION_TO_CAR, "Connection to car response is empty, treating as " + + "disconnected"); postValue(CarConnection.CONNECTION_TYPE_NOT_CONNECTED); return; } @@ -117,4 +127,17 @@ final class CarConnectionTypeLiveData extends LiveData<@ConnectionType Integer> queryForState(); } } + + @RequiresApi(33) + static class Api33Impl { + private Api33Impl() { + // Not instantiable + } + + @DoNotInline + static void registerExportedReceiver(Context context, BroadcastReceiver broadcastReceiver, + IntentFilter intentFilter) { + context.registerReceiver(broadcastReceiver, intentFilter, Context.RECEIVER_EXPORTED); + } + } }