1/*
2 * Copyright (C) 2012 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
17package android.support.v4.net;
18
19import static android.net.ConnectivityManager.TYPE_BLUETOOTH;
20import static android.net.ConnectivityManager.TYPE_ETHERNET;
21import static android.net.ConnectivityManager.TYPE_MOBILE;
22import static android.net.ConnectivityManager.TYPE_MOBILE_DUN;
23import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI;
24import static android.net.ConnectivityManager.TYPE_MOBILE_MMS;
25import static android.net.ConnectivityManager.TYPE_MOBILE_SUPL;
26import static android.net.ConnectivityManager.TYPE_WIFI;
27import static android.net.ConnectivityManager.TYPE_WIMAX;
28import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
29
30import android.content.Intent;
31import android.net.ConnectivityManager;
32import android.net.NetworkInfo;
33import android.os.Build;
34import android.support.annotation.IntDef;
35import android.support.annotation.RequiresPermission;
36import android.support.annotation.RestrictTo;
37
38import java.lang.annotation.Retention;
39import java.lang.annotation.RetentionPolicy;
40
41/**
42 * Helper for accessing features in {@link ConnectivityManager}.
43 */
44public final class ConnectivityManagerCompat {
45    /** @hide */
46    @RestrictTo(LIBRARY_GROUP)
47    @Retention(RetentionPolicy.SOURCE)
48    @IntDef(value = {
49            RESTRICT_BACKGROUND_STATUS_DISABLED,
50            RESTRICT_BACKGROUND_STATUS_WHITELISTED,
51            RESTRICT_BACKGROUND_STATUS_ENABLED,
52    })
53    public @interface RestrictBackgroundStatus {
54    }
55
56    /**
57     * Device is not restricting metered network activity while application is running on
58     * background.
59     */
60    public static final int RESTRICT_BACKGROUND_STATUS_DISABLED = 1;
61
62    /**
63     * Device is restricting metered network activity while application is running on background,
64     * but application is allowed to bypass it.
65     * <p>
66     * In this state, application should take action to mitigate metered network access.
67     * For example, a music streaming application should switch to a low-bandwidth bitrate.
68     */
69    public static final int RESTRICT_BACKGROUND_STATUS_WHITELISTED = 2;
70
71    /**
72     * Device is restricting metered network activity while application is running on background.
73     * <p>
74     * In this state, application should not try to use the network while running on background,
75     * because it would be denied.
76     */
77    public static final int RESTRICT_BACKGROUND_STATUS_ENABLED = 3;
78
79    /**
80     * Returns if the currently active data network is metered. A network is
81     * classified as metered when the user is sensitive to heavy data usage on
82     * that connection due to monetary costs, data limitations or
83     * battery/performance issues. You should check this before doing large
84     * data transfers, and warn the user or delay the operation until another
85     * network is available.
86     * <p>This method requires the caller to hold the permission
87     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
88     *
89     * @return {@code true} if large transfers should be avoided, otherwise
90     *        {@code false}.
91     */
92    @SuppressWarnings("deprecation")
93    @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
94    public static boolean isActiveNetworkMetered(ConnectivityManager cm) {
95        if (Build.VERSION.SDK_INT >= 16) {
96            return cm.isActiveNetworkMetered();
97        } else {
98            final NetworkInfo info = cm.getActiveNetworkInfo();
99            if (info == null) {
100                // err on side of caution
101                return true;
102            }
103
104            final int type = info.getType();
105            switch (type) {
106                case TYPE_MOBILE:
107                case TYPE_MOBILE_DUN:
108                case TYPE_MOBILE_HIPRI:
109                case TYPE_MOBILE_MMS:
110                case TYPE_MOBILE_SUPL:
111                case TYPE_WIMAX:
112                    return true;
113                case TYPE_WIFI:
114                case TYPE_BLUETOOTH:
115                case TYPE_ETHERNET:
116                    return false;
117                default:
118                    // err on side of caution
119                    return true;
120            }
121        }
122    }
123
124    /**
125     * Return the {@link NetworkInfo} that caused the given
126     * {@link ConnectivityManager#CONNECTIVITY_ACTION} broadcast. This obtains
127     * the current state from {@link ConnectivityManager} instead of using the
128     * potentially-stale value from
129     * {@link ConnectivityManager#EXTRA_NETWORK_INFO}. May be {@code null}.
130     */
131    @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
132    public static NetworkInfo getNetworkInfoFromBroadcast(ConnectivityManager cm, Intent intent) {
133        final NetworkInfo info = intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
134        if (info != null) {
135            return cm.getNetworkInfo(info.getType());
136        } else {
137            return null;
138        }
139    }
140
141    /**
142     * Determines if the calling application is subject to metered network restrictions while
143     * running on background.
144     *
145     * @return {@link #RESTRICT_BACKGROUND_STATUS_DISABLED},
146     *         {@link #RESTRICT_BACKGROUND_STATUS_ENABLED},
147     *         or {@link #RESTRICT_BACKGROUND_STATUS_WHITELISTED}
148     */
149    @RestrictBackgroundStatus
150    public static int getRestrictBackgroundStatus(ConnectivityManager cm) {
151        if (Build.VERSION.SDK_INT >= 24) {
152            return cm.getRestrictBackgroundStatus();
153        } else {
154            return RESTRICT_BACKGROUND_STATUS_ENABLED;
155        }
156    }
157
158    private ConnectivityManagerCompat() {}
159}
160