1 /* 2 * Copyright (C) 2017 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 17 package android.net; 18 19 import android.Manifest.permission; 20 import android.annotation.SystemApi; 21 import android.content.Context; 22 import android.os.Build; 23 import android.os.Handler; 24 import android.os.IBinder; 25 import android.os.RemoteException; 26 import android.util.Log; 27 28 import com.android.internal.util.Preconditions; 29 30 import java.util.concurrent.Executor; 31 32 /** 33 * The base class for implementing a network recommendation provider. 34 * <p> 35 * A network recommendation provider is any application which: 36 * <ul> 37 * <li>Is granted the {@link permission#SCORE_NETWORKS} permission. 38 * <li>Is granted the {@link permission#ACCESS_COARSE_LOCATION} permission. 39 * <li>Includes a Service for the {@link NetworkScoreManager#ACTION_RECOMMEND_NETWORKS} intent 40 * which is protected by the {@link permission#BIND_NETWORK_RECOMMENDATION_SERVICE} permission. 41 * </ul> 42 * <p> 43 * Implementations are required to implement the abstract methods in this class and return the 44 * result of {@link #getBinder()} from the <code>onBind()</code> method in their Service. 45 * <p> 46 * The default network recommendation provider is controlled via the 47 * <code>config_defaultNetworkRecommendationProviderPackage</code> config key. 48 * @hide 49 */ 50 @SystemApi 51 public abstract class NetworkRecommendationProvider { 52 private static final String TAG = "NetworkRecProvider"; 53 private static final boolean VERBOSE = Build.IS_DEBUGGABLE && Log.isLoggable(TAG, Log.VERBOSE); 54 private final IBinder mService; 55 56 /** 57 * Constructs a new instance. 58 * @param context the current context instance. Cannot be {@code null}. 59 * @param executor used to execute the incoming requests. Cannot be {@code null}. 60 */ NetworkRecommendationProvider(Context context, Executor executor)61 public NetworkRecommendationProvider(Context context, Executor executor) { 62 Preconditions.checkNotNull(context); 63 Preconditions.checkNotNull(executor); 64 mService = new ServiceWrapper(context, executor); 65 } 66 67 /** 68 * Invoked when network scores have been requested. 69 * <p> 70 * Use {@link NetworkScoreManager#updateScores(ScoredNetwork[])} to respond to score requests. 71 * 72 * @param networks a non-empty array of {@link NetworkKey}s to score. 73 */ onRequestScores(NetworkKey[] networks)74 public abstract void onRequestScores(NetworkKey[] networks); 75 76 /** 77 * Services that can handle {@link NetworkScoreManager#ACTION_RECOMMEND_NETWORKS} should 78 * return this Binder from their <code>onBind()</code> method. 79 */ getBinder()80 public final IBinder getBinder() { 81 return mService; 82 } 83 84 /** 85 * A wrapper around INetworkRecommendationProvider that dispatches to the provided Handler. 86 */ 87 private final class ServiceWrapper extends INetworkRecommendationProvider.Stub { 88 private final Context mContext; 89 private final Executor mExecutor; 90 private final Handler mHandler; 91 ServiceWrapper(Context context, Executor executor)92 ServiceWrapper(Context context, Executor executor) { 93 mContext = context; 94 mExecutor = executor; 95 mHandler = null; 96 } 97 98 @Override requestScores(final NetworkKey[] networks)99 public void requestScores(final NetworkKey[] networks) throws RemoteException { 100 enforceCallingPermission(); 101 if (networks != null && networks.length > 0) { 102 execute(new Runnable() { 103 @Override 104 public void run() { 105 onRequestScores(networks); 106 } 107 }); 108 } 109 } 110 execute(Runnable command)111 private void execute(Runnable command) { 112 if (mExecutor != null) { 113 mExecutor.execute(command); 114 } else { 115 mHandler.post(command); 116 } 117 } 118 enforceCallingPermission()119 private void enforceCallingPermission() { 120 if (mContext != null) { 121 mContext.enforceCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES, 122 "Permission denied."); 123 } 124 } 125 } 126 } 127