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