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