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