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