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