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