summaryrefslogtreecommitdiff
path: root/android/net/NetworkScoreManager.java
blob: 50dd468aa9053847ddbb255a4d969da17fc575ce (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
/*
 * Copyright (C) 2014 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 android.net;

import android.Manifest.permission;
import android.annotation.IntDef;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.content.Context;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.ServiceManager.ServiceNotFoundException;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.List;

/**
 * Class that manages communication between network subsystems and a network scorer.
 *
 * <p>A network scorer is any application which:
 * <ul>
 * <li>Is granted the {@link permission#SCORE_NETWORKS} permission.
 * <li>Is granted the {@link permission#ACCESS_COARSE_LOCATION} permission.
 * <li>Include a Service for the {@link #ACTION_RECOMMEND_NETWORKS} action
 *     protected by the {@link permission#BIND_NETWORK_RECOMMENDATION_SERVICE}
 *     permission.
 * </ul>
 *
 * @hide
 */
@SystemApi
@SystemService(Context.NETWORK_SCORE_SERVICE)
public class NetworkScoreManager {
    /**
     * Activity action: ask the user to change the active network scorer. This will show a dialog
     * that asks the user whether they want to replace the current active scorer with the one
     * specified in {@link #EXTRA_PACKAGE_NAME}. The activity will finish with RESULT_OK if the
     * active scorer was changed or RESULT_CANCELED if it failed for any reason.
     */
    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
    public static final String ACTION_CHANGE_ACTIVE = "android.net.scoring.CHANGE_ACTIVE";

    /**
     * Extra used with {@link #ACTION_CHANGE_ACTIVE} to specify the new scorer package. Set with
     * {@link android.content.Intent#putExtra(String, String)}.
     */
    public static final String EXTRA_PACKAGE_NAME = "packageName";

    /**
     * Broadcast action: new network scores are being requested. This intent will only be delivered
     * to the current active scorer app. That app is responsible for scoring the networks and
     * calling {@link #updateScores} when complete. The networks to score are specified in
     * {@link #EXTRA_NETWORKS_TO_SCORE}, and will generally consist of all networks which have been
     * configured by the user as well as any open networks.
     *
     * <p class="note">This is a protected intent that can only be sent by the system.
     */
    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    public static final String ACTION_SCORE_NETWORKS = "android.net.scoring.SCORE_NETWORKS";

    /**
     * Extra used with {@link #ACTION_SCORE_NETWORKS} to specify the networks to be scored, as an
     * array of {@link NetworkKey}s. Can be obtained with
     * {@link android.content.Intent#getParcelableArrayExtra(String)}}.
     */
    public static final String EXTRA_NETWORKS_TO_SCORE = "networksToScore";

    /**
     * Activity action: launch an activity for configuring a provider for the feature that connects
     * and secures open wifi networks available before enabling it. Applications that enable this
     * feature must provide an activity for this action. The framework will launch this activity
     * which must return RESULT_OK if the feature should be enabled.
     */
    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
    public static final String ACTION_CUSTOM_ENABLE = "android.net.scoring.CUSTOM_ENABLE";

    /**
     * Meta-data specified on a {@link NetworkRecommendationProvider} that provides a user-visible
     * label of the recommendation service.
     * @hide
     */
    public static final String RECOMMENDATION_SERVICE_LABEL_META_DATA =
            "android.net.scoring.recommendation_service_label";

    /**
     * Meta-data specified on a {@link NetworkRecommendationProvider} that specified the package
     * name of the application that connects and secures open wifi networks automatically. The
     * specified package must provide an Activity for {@link #ACTION_CUSTOM_ENABLE}.
     * @hide
     */
    public static final String USE_OPEN_WIFI_PACKAGE_META_DATA =
            "android.net.wifi.use_open_wifi_package";

    /**
     * Meta-data specified on a {@link NetworkRecommendationProvider} that specifies the
     * {@link android.app.NotificationChannel} ID used to post open network notifications.
     * @hide
     */
    public static final String NETWORK_AVAILABLE_NOTIFICATION_CHANNEL_ID_META_DATA =
            "android.net.wifi.notification_channel_id_network_available";

    /**
     * Broadcast action: the active scorer has been changed. Scorer apps may listen to this to
     * perform initialization once selected as the active scorer, or clean up unneeded resources
     * if another scorer has been selected. This is an explicit broadcast only sent to the
     * previous scorer and new scorer. Note that it is unnecessary to clear existing scores as
     * this is handled by the system.
     *
     * <p>The new scorer will be specified in {@link #EXTRA_NEW_SCORER}.
     *
     * <p class="note">This is a protected intent that can only be sent by the system.
     */
    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    public static final String ACTION_SCORER_CHANGED = "android.net.scoring.SCORER_CHANGED";

    /**
     * Service action: Used to discover and bind to a network recommendation provider.
     * Implementations should return {@link NetworkRecommendationProvider#getBinder()} from
     * their <code>onBind()</code> method.
     */
    @SdkConstant(SdkConstantType.SERVICE_ACTION)
    public static final String ACTION_RECOMMEND_NETWORKS = "android.net.action.RECOMMEND_NETWORKS";

    /**
     * Extra used with {@link #ACTION_SCORER_CHANGED} to specify the newly selected scorer's package
     * name. Will be null if scoring was disabled. Can be obtained with
     * {@link android.content.Intent#getStringExtra(String)}.
     */
    public static final String EXTRA_NEW_SCORER = "newScorer";

    /** @hide */
    @IntDef({CACHE_FILTER_NONE, CACHE_FILTER_CURRENT_NETWORK, CACHE_FILTER_SCAN_RESULTS})
    @Retention(RetentionPolicy.SOURCE)
    public @interface CacheUpdateFilter {}

    /**
     * Do not filter updates sent to the cache.
     * @hide
     */
    public static final int CACHE_FILTER_NONE = 0;

    /**
     * Only send cache updates when the network matches the connected network.
     * @hide
     */
    public static final int CACHE_FILTER_CURRENT_NETWORK = 1;

    /**
     * Only send cache updates when the network is part of the current scan result set.
     * @hide
     */
    public static final int CACHE_FILTER_SCAN_RESULTS = 2;

    /** @hide */
    @IntDef({RECOMMENDATIONS_ENABLED_FORCED_OFF, RECOMMENDATIONS_ENABLED_OFF,
            RECOMMENDATIONS_ENABLED_ON})
    @Retention(RetentionPolicy.SOURCE)
    public @interface RecommendationsEnabledSetting {}

    /**
     * Recommendations have been forced off.
     * <p>
     * This value is never set by any of the NetworkScore classes, it must be set via other means.
     * This state is also "sticky" and we won't transition out of this state once entered. To move
     * to a different state this value has to be explicitly set to a different value via
     * other means.
     * @hide
     */
    public static final int RECOMMENDATIONS_ENABLED_FORCED_OFF = -1;

    /**
     * Recommendations are not enabled.
     * <p>
     * This is a transient state that can be entered when the default recommendation app is enabled
     * but no longer valid. This state will transition to RECOMMENDATIONS_ENABLED_ON when a valid
     * recommendation app is enabled.
     * @hide
     */
    public static final int RECOMMENDATIONS_ENABLED_OFF = 0;

    /**
     * Recommendations are enabled.
     * <p>
     * This is a transient state that means a valid recommendation app is active. This state will
     * transition to RECOMMENDATIONS_ENABLED_OFF if the current and default recommendation apps
     * become invalid.
     * @hide
     */
    public static final int RECOMMENDATIONS_ENABLED_ON = 1;

    private final Context mContext;
    private final INetworkScoreService mService;

    /** @hide */
    public NetworkScoreManager(Context context) throws ServiceNotFoundException {
        mContext = context;
        mService = INetworkScoreService.Stub
                .asInterface(ServiceManager.getServiceOrThrow(Context.NETWORK_SCORE_SERVICE));
    }

    /**
     * Obtain the package name of the current active network scorer.
     *
     * <p>At any time, only one scorer application will receive {@link #ACTION_SCORE_NETWORKS}
     * broadcasts and be allowed to call {@link #updateScores}. Applications may use this method to
     * determine the current scorer and offer the user the ability to select a different scorer via
     * the {@link #ACTION_CHANGE_ACTIVE} intent.
     * @return the full package name of the current active scorer, or null if there is no active
     *         scorer.
     * @throws SecurityException if the caller doesn't hold either {@link permission#SCORE_NETWORKS}
     *                           or {@link permission#REQUEST_NETWORK_SCORES} permissions.
     */
    @RequiresPermission(anyOf = {android.Manifest.permission.SCORE_NETWORKS,
                                 android.Manifest.permission.REQUEST_NETWORK_SCORES})
    public String getActiveScorerPackage() {
        try {
            return mService.getActiveScorerPackage();
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * Returns metadata about the active scorer or <code>null</code> if there is no active scorer.
     *
     * @throws SecurityException if the caller does not hold the
     *         {@link permission#REQUEST_NETWORK_SCORES} permission.
     * @hide
     */
    @Nullable
    @RequiresPermission(android.Manifest.permission.REQUEST_NETWORK_SCORES)
    public NetworkScorerAppData getActiveScorer() {
        try {
            return mService.getActiveScorer();
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * Returns the list of available scorer apps. The list will be empty if there are
     * no valid scorers.
     *
     * @throws SecurityException if the caller does not hold the
     *         {@link permission#REQUEST_NETWORK_SCORES} permission.
     * @hide
     */
    @RequiresPermission(android.Manifest.permission.REQUEST_NETWORK_SCORES)
    public List<NetworkScorerAppData> getAllValidScorers() {
        try {
            return mService.getAllValidScorers();
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * Update network scores.
     *
     * <p>This may be called at any time to re-score active networks. Scores will generally be
     * updated quickly, but if this method is called too frequently, the scores may be held and
     * applied at a later time.
     *
     * @param networks the networks which have been scored by the scorer.
     * @return whether the update was successful.
     * @throws SecurityException if the caller is not the active scorer.
     */
    @RequiresPermission(android.Manifest.permission.SCORE_NETWORKS)
    public boolean updateScores(ScoredNetwork[] networks) throws SecurityException {
        try {
            return mService.updateScores(networks);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * Clear network scores.
     *
     * <p>Should be called when all scores need to be invalidated, i.e. because the scoring
     * algorithm has changed and old scores can no longer be compared to future scores.
     *
     * <p>Note that scores will be cleared automatically when the active scorer changes, as scores
     * from one scorer cannot be compared to those from another scorer.
     *
     * @return whether the clear was successful.
     * @throws SecurityException if the caller is not the active scorer or if the caller doesn't
     *                           hold the {@link permission#REQUEST_NETWORK_SCORES} permission.
     */
    @RequiresPermission(anyOf = {android.Manifest.permission.SCORE_NETWORKS,
                                 android.Manifest.permission.REQUEST_NETWORK_SCORES})
    public boolean clearScores() throws SecurityException {
        try {
            return mService.clearScores();
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * Set the active scorer to a new package and clear existing scores.
     *
     * <p>Should never be called directly without obtaining user consent. This can be done by using
     * the {@link #ACTION_CHANGE_ACTIVE} broadcast, or using a custom configuration activity.
     *
     * @return true if the operation succeeded, or false if the new package is not a valid scorer.
     * @throws SecurityException if the caller doesn't hold either {@link permission#SCORE_NETWORKS}
     *                           or {@link permission#REQUEST_NETWORK_SCORES} permissions.
     * @hide
     */
    @SystemApi
    @RequiresPermission(anyOf = {android.Manifest.permission.SCORE_NETWORKS,
                                 android.Manifest.permission.REQUEST_NETWORK_SCORES})
    public boolean setActiveScorer(String packageName) throws SecurityException {
        try {
            return mService.setActiveScorer(packageName);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * Turn off network scoring.
     *
     * <p>May only be called by the current scorer app, or the system.
     *
     * @throws SecurityException if the caller is not the active scorer or if the caller doesn't
     *                           hold the {@link permission#REQUEST_NETWORK_SCORES} permission.
     */
    @RequiresPermission(anyOf = {android.Manifest.permission.SCORE_NETWORKS,
                                 android.Manifest.permission.REQUEST_NETWORK_SCORES})
    public void disableScoring() throws SecurityException {
        try {
            mService.disableScoring();
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * Request scoring for networks.
     *
     * @return true if the broadcast was sent, or false if there is no active scorer.
     * @throws SecurityException if the caller does not hold the
     *         {@link permission#REQUEST_NETWORK_SCORES} permission.
     * @hide
     */
    @RequiresPermission(android.Manifest.permission.REQUEST_NETWORK_SCORES)
    public boolean requestScores(NetworkKey[] networks) throws SecurityException {
        try {
            return mService.requestScores(networks);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * Register a network score cache.
     *
     * @param networkType the type of network this cache can handle. See {@link NetworkKey#type}.
     * @param scoreCache implementation of {@link INetworkScoreCache} to store the scores.
     * @throws SecurityException if the caller does not hold the
     *         {@link permission#REQUEST_NETWORK_SCORES} permission.
     * @throws IllegalArgumentException if a score cache is already registered for this type.
     * @deprecated equivalent to registering for cache updates with CACHE_FILTER_NONE.
     * @hide
     */
    @RequiresPermission(android.Manifest.permission.REQUEST_NETWORK_SCORES)
    @Deprecated // migrate to registerNetworkScoreCache(int, INetworkScoreCache, int)
    public void registerNetworkScoreCache(int networkType, INetworkScoreCache scoreCache) {
        registerNetworkScoreCache(networkType, scoreCache, CACHE_FILTER_NONE);
    }

    /**
     * Register a network score cache.
     *
     * @param networkType the type of network this cache can handle. See {@link NetworkKey#type}
     * @param scoreCache implementation of {@link INetworkScoreCache} to store the scores
     * @param filterType the {@link CacheUpdateFilter} to apply
     * @throws SecurityException if the caller does not hold the
     *         {@link permission#REQUEST_NETWORK_SCORES} permission.
     * @throws IllegalArgumentException if a score cache is already registered for this type.
     * @hide
     */
    @RequiresPermission(android.Manifest.permission.REQUEST_NETWORK_SCORES)
    public void registerNetworkScoreCache(int networkType, INetworkScoreCache scoreCache,
            @CacheUpdateFilter int filterType) {
        try {
            mService.registerNetworkScoreCache(networkType, scoreCache, filterType);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * Unregister a network score cache.
     *
     * @param networkType the type of network this cache can handle. See {@link NetworkKey#type}.
     * @param scoreCache implementation of {@link INetworkScoreCache} to store the scores.
     * @throws SecurityException if the caller does not hold the
     *         {@link permission#REQUEST_NETWORK_SCORES} permission.
     * @throws IllegalArgumentException if a score cache is already registered for this type.
     * @hide
     */
    @RequiresPermission(android.Manifest.permission.REQUEST_NETWORK_SCORES)
    public void unregisterNetworkScoreCache(int networkType, INetworkScoreCache scoreCache) {
        try {
            mService.unregisterNetworkScoreCache(networkType, scoreCache);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * Determine whether the application with the given UID is the enabled scorer.
     *
     * @param callingUid the UID to check
     * @return true if the provided UID is the active scorer, false otherwise.
     * @throws SecurityException if the caller does not hold the
     *         {@link permission#REQUEST_NETWORK_SCORES} permission.
     * @hide
     */
    @RequiresPermission(android.Manifest.permission.REQUEST_NETWORK_SCORES)
    public boolean isCallerActiveScorer(int callingUid) {
        try {
            return mService.isCallerActiveScorer(callingUid);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }
}