1 /* 2 * Copyright (C) 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.google.android.car.networking.preferenceupdater.components; 17 18 import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PAID; 19 import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK; 20 import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY; 21 import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY; 22 23 import android.annotation.NonNull; 24 import android.annotation.Nullable; 25 import android.content.Context; 26 import android.net.ConnectivityManager; 27 import android.net.OemNetworkPreferences; 28 import android.util.Log; 29 import android.util.SparseArray; 30 31 import java.util.Set; 32 import java.util.concurrent.CompletableFuture; 33 import java.util.concurrent.TimeUnit; 34 35 /** Class wraps OemNetworkPreferences (PANS) APIs and routine around it */ 36 public final class OemNetworkPreferencesAdapter { 37 private static final String TAG = OemNetworkPreferencesAdapter.class.getSimpleName(); 38 39 // Seconds to wait for setOemNetworkPreference() call to complete 40 private static final int PANS_CALL_TIMEOUT_SEC = 5; 41 public static final int[] OEM_NETWORK_PREFERENCE_ARRAY = 42 new int[] { 43 OEM_NETWORK_PREFERENCE_OEM_PAID, 44 OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK, 45 OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY, 46 OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY, 47 }; 48 49 private final ConnectivityManager mConnectivityManager; 50 private final Context mContext; 51 52 private static class OemListenerCallback implements Runnable { 53 final CompletableFuture<Object> mDone = new CompletableFuture<>(); 54 55 @Override run()56 public void run() { 57 mDone.complete(new Object()); 58 } 59 expectOnComplete()60 void expectOnComplete() throws Exception { 61 mDone.get(PANS_CALL_TIMEOUT_SEC, TimeUnit.SECONDS); 62 } 63 } 64 OemNetworkPreferencesAdapter(Context ctx)65 public OemNetworkPreferencesAdapter(Context ctx) { 66 mConnectivityManager = ctx.getSystemService(ConnectivityManager.class); 67 mContext = ctx; 68 } 69 70 /** 71 * Accepts mapping <OemNetworkPreference.<id>> -> <Set of applications> and calls PANS APIs to 72 * apply them. 73 */ applyPreference(@ullable SparseArray<Set<String>> preference)74 public void applyPreference(@Nullable SparseArray<Set<String>> preference) { 75 // We want to create listener and wait for the call to end before proceeding further. 76 // To address that better, we will use CompletableFuture. 77 final OemListenerCallback listener = new OemListenerCallback(); 78 mConnectivityManager.setOemNetworkPreference( 79 generatePrefsFrom(preference), r -> r.run(), listener); 80 // We don't want to be blocked and wait for results forver, thus we will wait for 5 seconds 81 // before cancelling future. 82 try { 83 listener.expectOnComplete(); 84 Log.d(TAG, "New OEM Network Preferences are now applied."); 85 } catch (Exception ex) { 86 /** 87 * From 4 potential exceptions: - CancellationException - if this future was cancelled - 88 * ExecutionException - if this future completed exceptionally - InterruptedException - 89 * if the current thread was interrupted while waiting - TimeoutException - if the wait 90 * timed out For now since we are not handling exceptions customly, we simply print the 91 * exception and silence it. 92 * 93 * TODO(b/183749278): Improve exceptoin handling in this case. 94 */ 95 Log.e(TAG, "Call into setOemNetworkPreference() has failed with exception", ex); 96 } 97 } 98 99 /** 100 * This should reset the OEM Network preferences set by this application or by any other 101 * application which calls into setOemNetworkPreferences() API. 102 */ resetNetworkPreferences()103 public void resetNetworkPreferences() { 104 // Considering that applyPreference will call into setOemNetworkPreference() all we need 105 // is to pass null and it will delete PersonalStorage data and will reset PANS. 106 applyPreference(null); 107 } 108 generatePrefsFrom(@ullable SparseArray<Set<String>> preference)109 private OemNetworkPreferences generatePrefsFrom(@Nullable SparseArray<Set<String>> preference) { 110 OemNetworkPreferences.Builder builder = new OemNetworkPreferences.Builder(); 111 112 // Iterate through all available oem network preference types 113 for (int type : OEM_NETWORK_PREFERENCE_ARRAY) { 114 Set<String> apps = 115 preference == null 116 ? OemAppsManager.getDefaultAppsFor(mContext, type) 117 : preference.get(type); 118 addPreferenceFromAppsSet(type, builder, apps); 119 } 120 return builder.build(); 121 } 122 addPreferenceFromAppsSet( int type, @NonNull OemNetworkPreferences.Builder builder, @NonNull Set<String> apps)123 private void addPreferenceFromAppsSet( 124 int type, @NonNull OemNetworkPreferences.Builder builder, @NonNull Set<String> apps) { 125 for (String app : apps) { 126 builder.addNetworkPreference(app, type); 127 } 128 } 129 } 130