summaryrefslogtreecommitdiffstats
path: root/core/java
diff options
context:
space:
mode:
Diffstat (limited to 'core/java')
-rw-r--r--core/java/android/app/Activity.java2
-rw-r--r--core/java/android/app/Dialog.java2
-rw-r--r--core/java/android/app/Fragment.java1
-rw-r--r--core/java/android/app/FragmentManager.java2
-rw-r--r--core/java/android/app/INotificationManager.aidl1
-rw-r--r--core/java/android/app/NotificationManager.java51
-rw-r--r--core/java/android/app/UiModeManager.java7
-rw-r--r--core/java/android/app/admin/DeviceAdminReceiver.java13
-rw-r--r--core/java/android/content/Context.java15
-rw-r--r--core/java/android/content/pm/RegisteredServicesCache.java243
-rw-r--r--core/java/android/database/DatabaseUtils.java28
-rw-r--r--core/java/android/hardware/Sensor.java92
-rw-r--r--core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java12
-rw-r--r--core/java/android/midi/MidiDeviceServer.java4
-rw-r--r--core/java/android/midi/MidiInputPort.java2
-rw-r--r--core/java/android/midi/MidiManager.java10
-rw-r--r--core/java/android/midi/MidiOutputPort.java2
-rw-r--r--core/java/android/midi/MidiReceiver.java4
-rw-r--r--core/java/android/net/ConnectivityManager.java4
-rw-r--r--core/java/android/net/ProxyInfo.java7
-rw-r--r--core/java/android/net/http/AndroidHttpClient.java527
-rw-r--r--core/java/android/net/http/AndroidHttpClientConnection.java460
-rw-r--r--core/java/android/net/http/CertificateChainValidator.java279
-rw-r--r--core/java/android/net/http/Connection.java575
-rw-r--r--core/java/android/net/http/ConnectionThread.java137
-rw-r--r--core/java/android/net/http/DelegatingSSLSession.java158
-rw-r--r--core/java/android/net/http/EventHandler.java131
-rw-r--r--core/java/android/net/http/Headers.java521
-rw-r--r--core/java/android/net/http/HttpAuthHeader.java424
-rw-r--r--core/java/android/net/http/HttpConnection.java93
-rw-r--r--core/java/android/net/http/HttpLog.java43
-rw-r--r--core/java/android/net/http/HttpResponseCache.java4
-rw-r--r--core/java/android/net/http/HttpsConnection.java433
-rw-r--r--core/java/android/net/http/IdleCache.java175
-rw-r--r--core/java/android/net/http/LoggingEventHandler.java92
-rw-r--r--core/java/android/net/http/Request.java526
-rw-r--r--core/java/android/net/http/RequestFeeder.java42
-rw-r--r--core/java/android/net/http/RequestHandle.java466
-rw-r--r--core/java/android/net/http/RequestQueue.java542
-rw-r--r--core/java/android/provider/Settings.java598
-rw-r--r--core/java/android/service/dreams/DreamService.java2
-rw-r--r--core/java/android/service/notification/NotificationListenerService.java15
-rw-r--r--core/java/android/text/SpannableStringBuilder.java550
-rw-r--r--core/java/android/text/format/DateUtils.java154
-rw-r--r--core/java/android/transition/ArcMotion.java3
-rw-r--r--core/java/android/transition/CircularPropagation.java15
-rw-r--r--core/java/android/transition/Explode.java24
-rw-r--r--core/java/android/transition/PatternPathMotion.java12
-rw-r--r--core/java/android/transition/SidePropagation.java1
-rw-r--r--core/java/android/transition/Transition.java12
-rw-r--r--core/java/android/transition/Visibility.java4
-rw-r--r--core/java/android/util/AtomicFile.java2
-rw-r--r--core/java/android/util/DisplayMetrics.java7
-rw-r--r--core/java/android/view/View.java1
-rw-r--r--core/java/android/view/ViewGroup.java8
-rw-r--r--core/java/android/view/Window.java1
-rw-r--r--core/java/android/view/accessibility/AccessibilityCache.java32
-rw-r--r--core/java/android/view/inputmethod/InputMethodManager.java24
-rw-r--r--core/java/android/webkit/LegacyErrorStrings.java33
-rw-r--r--core/java/android/widget/CompoundButton.java62
-rw-r--r--core/java/android/widget/EdgeEffect.java5
-rw-r--r--core/java/android/widget/Editor.java4
-rw-r--r--core/java/com/android/internal/http/multipart/ByteArrayPartSource.java86
-rw-r--r--core/java/com/android/internal/http/multipart/FilePart.java259
-rw-r--r--core/java/com/android/internal/http/multipart/FilePartSource.java131
-rw-r--r--core/java/com/android/internal/http/multipart/MultipartEntity.java236
-rw-r--r--core/java/com/android/internal/http/multipart/Part.java445
-rw-r--r--core/java/com/android/internal/http/multipart/PartBase.java150
-rw-r--r--core/java/com/android/internal/http/multipart/PartSource.java72
-rw-r--r--core/java/com/android/internal/http/multipart/StringPart.java156
-rw-r--r--core/java/com/android/internal/os/ZygoteInit.java2
-rw-r--r--core/java/com/android/internal/widget/ButtonBarLayout.java91
-rw-r--r--core/java/org/apache/http/conn/ConnectTimeoutException.java69
-rw-r--r--core/java/org/apache/http/conn/scheme/HostNameResolver.java47
-rw-r--r--core/java/org/apache/http/conn/scheme/LayeredSocketFactory.java77
-rw-r--r--core/java/org/apache/http/conn/scheme/SocketFactory.java143
-rw-r--r--core/java/org/apache/http/conn/ssl/AbstractVerifier.java288
-rw-r--r--core/java/org/apache/http/conn/ssl/AllowAllHostnameVerifier.java59
-rw-r--r--core/java/org/apache/http/conn/ssl/BrowserCompatHostnameVerifier.java67
-rw-r--r--core/java/org/apache/http/conn/ssl/SSLSocketFactory.java408
-rw-r--r--core/java/org/apache/http/conn/ssl/StrictHostnameVerifier.java74
-rw-r--r--core/java/org/apache/http/conn/ssl/X509HostnameVerifier.java91
-rw-r--r--core/java/org/apache/http/conn/ssl/package.html40
-rw-r--r--core/java/org/apache/http/params/CoreConnectionPNames.java136
-rw-r--r--core/java/org/apache/http/params/HttpConnectionParams.java229
-rw-r--r--core/java/org/apache/http/params/HttpParams.java192
86 files changed, 3510 insertions, 7737 deletions
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index e95fbfc..aa1c70e 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -743,6 +743,7 @@ public class Activity extends ContextThemeWrapper
final FragmentManagerImpl mFragments = new FragmentManagerImpl();
final FragmentContainer mContainer = new FragmentContainer() {
@Override
+ @Nullable
public View findViewById(int id) {
return Activity.this.findViewById(id);
}
@@ -2068,6 +2069,7 @@ public class Activity extends ContextThemeWrapper
*
* @return The view if found or null otherwise.
*/
+ @Nullable
public View findViewById(int id) {
return getWindow().findViewById(id);
}
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index 70e6e5a..a3662b2 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -18,6 +18,7 @@ package android.app;
import com.android.internal.app.WindowDecorActionBar;
+import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.Context;
import android.content.ContextWrapper;
@@ -476,6 +477,7 @@ public class Dialog implements DialogInterface, Window.Callback,
* @param id the identifier of the view to find
* @return The view with the given id or null.
*/
+ @Nullable
public View findViewById(int id) {
return mWindow.findViewById(id);
}
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index ab28d95..f319309 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -2008,6 +2008,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
mChildFragmentManager = new FragmentManagerImpl();
mChildFragmentManager.attachActivity(mActivity, new FragmentContainer() {
@Override
+ @Nullable
public View findViewById(int id) {
if (mView == null) {
throw new IllegalStateException("Fragment does not have a view");
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index ccceef4..afdc917 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -19,6 +19,7 @@ package android.app;
import android.animation.Animator;
import android.animation.AnimatorInflater;
import android.animation.AnimatorListenerAdapter;
+import android.annotation.Nullable;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.TypedArray;
@@ -394,6 +395,7 @@ final class FragmentManagerState implements Parcelable {
* Callbacks from FragmentManagerImpl to its container.
*/
interface FragmentContainer {
+ @Nullable
public View findViewById(int id);
public boolean hasView();
}
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 88b9080..5d864df 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -75,6 +75,7 @@ interface INotificationManager
ZenModeConfig getZenModeConfig();
boolean setZenModeConfig(in ZenModeConfig config);
+ oneway void setZenMode(int mode);
oneway void notifyConditions(String pkg, in IConditionProvider provider, in Condition[] conditions);
oneway void requestZenModeConditions(in IConditionListener callback, int relevance);
oneway void setZenModeCondition(in Condition condition);
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index cf54107..479327d 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -27,6 +27,9 @@ import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.StrictMode;
import android.os.UserHandle;
+import android.service.notification.Condition;
+import android.service.notification.IConditionListener;
+import android.service.notification.ZenModeConfig;
import android.util.Log;
/**
@@ -276,5 +279,53 @@ public class NotificationManager
}
}
+ /**
+ * @hide
+ */
+ public void setZenMode(int mode) {
+ INotificationManager service = getService();
+ try {
+ service.setZenMode(mode);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public void requestZenModeConditions(IConditionListener listener, int relevance) {
+ INotificationManager service = getService();
+ try {
+ service.requestZenModeConditions(listener, relevance);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public void setZenModeCondition(Condition exitCondition) {
+ INotificationManager service = getService();
+ try {
+ service.setZenModeCondition(exitCondition);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public Condition getZenModeCondition() {
+ INotificationManager service = getService();
+ try {
+ final ZenModeConfig config = service.getZenModeConfig();
+ if (config != null) {
+ return config.exitCondition;
+ }
+ } catch (RemoteException e) {
+ }
+ return null;
+ }
+
private Context mContext;
}
diff --git a/core/java/android/app/UiModeManager.java b/core/java/android/app/UiModeManager.java
index 0a255f7..0f6ce12 100644
--- a/core/java/android/app/UiModeManager.java
+++ b/core/java/android/app/UiModeManager.java
@@ -219,10 +219,9 @@ public class UiModeManager {
}
/**
- * Returns the currently configured night mode.
- *
- * @return {@link #MODE_NIGHT_NO}, {@link #MODE_NIGHT_YES}, or
- * {@link #MODE_NIGHT_AUTO}. When an error occurred -1 is returned.
+ * @return the currently configured night mode. May be one of
+ * {@link #MODE_NIGHT_NO}, {@link #MODE_NIGHT_YES},
+ * {@link #MODE_NIGHT_AUTO}, or -1 on error.
*/
public int getNightMode() {
if (mService != null) {
diff --git a/core/java/android/app/admin/DeviceAdminReceiver.java b/core/java/android/app/admin/DeviceAdminReceiver.java
index e9cce51..381d851 100644
--- a/core/java/android/app/admin/DeviceAdminReceiver.java
+++ b/core/java/android/app/admin/DeviceAdminReceiver.java
@@ -170,10 +170,10 @@ public class DeviceAdminReceiver extends BroadcastReceiver {
* lock task mode from an authorized package. The extra {@link #EXTRA_LOCK_TASK_PACKAGE}
* will describe the authorized package using lock task mode.
*
- * @see DevicePolicyManager#isLockTaskPermitted(String)
- *
* <p>The calling device admin must be the device owner or profile
* owner to receive this broadcast.
+ *
+ * @see DevicePolicyManager#isLockTaskPermitted(String)
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_LOCK_TASK_ENTERING
@@ -183,20 +183,19 @@ public class DeviceAdminReceiver extends BroadcastReceiver {
* Action sent to a device administrator to notify that the device is exiting
* lock task mode from an authorized package.
*
- * @see DevicePolicyManager#isLockTaskPermitted(String)
- *
* <p>The calling device admin must be the device owner or profile
* owner to receive this broadcast.
+ *
+ * @see DevicePolicyManager#isLockTaskPermitted(String)
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_LOCK_TASK_EXITING
= "android.app.action.LOCK_TASK_EXITING";
/**
- * A boolean describing whether the device is currently entering or exiting
- * lock task mode.
+ * A string containing the name of the package entering lock task mode.
*
- * @see #ACTION_LOCK_TASK_CHANGED
+ * @see #ACTION_LOCK_TASK_ENTERING
*/
public static final String EXTRA_LOCK_TASK_PACKAGE =
"android.app.extra.LOCK_TASK_PACKAGE";
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index dec2524..df620d0 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -2149,17 +2149,21 @@ public abstract class Context {
WIFI_PASSPOINT_SERVICE,
WIFI_P2P_SERVICE,
WIFI_SCANNING_SERVICE,
+ //@hide: WIFI_RTT_SERVICE,
//@hide: ETHERNET_SERVICE,
WIFI_RTT_SERVICE,
NSD_SERVICE,
AUDIO_SERVICE,
+ //@hide: FINGERPRINT_SERVICE,
MEDIA_ROUTER_SERVICE,
TELEPHONY_SERVICE,
+ TELEPHONY_SUBSCRIPTION_SERVICE,
TELECOM_SERVICE,
CLIPBOARD_SERVICE,
INPUT_METHOD_SERVICE,
TEXT_SERVICES_MANAGER_SERVICE,
APPWIDGET_SERVICE,
+ //@hide: VOICE_INTERACTION_MANAGER_SERVICE,
//@hide: BACKUP_SERVICE,
DROPBOX_SERVICE,
DEVICE_POLICY_SERVICE,
@@ -2171,16 +2175,23 @@ public abstract class Context {
USB_SERVICE,
LAUNCHER_APPS_SERVICE,
//@hide: SERIAL_SERVICE,
+ //@hide: HDMI_CONTROL_SERVICE,
INPUT_SERVICE,
DISPLAY_SERVICE,
- //@hide: SCHEDULING_POLICY_SERVICE,
USER_SERVICE,
- //@hide: APP_OPS_SERVICE
+ RESTRICTIONS_SERVICE,
+ APP_OPS_SERVICE,
CAMERA_SERVICE,
PRINT_SERVICE,
+ CONSUMER_IR_SERVICE,
+ //@hide: TRUST_SERVICE,
+ TV_INPUT_SERVICE,
+ //@hide: NETWORK_SCORE_SERVICE,
+ USAGE_STATS_SERVICE,
MEDIA_SESSION_SERVICE,
BATTERY_SERVICE,
JOB_SCHEDULER_SERVICE,
+ //@hide: PERSISTENT_DATA_BLOCK_SERVICE,
MEDIA_PROJECTION_SERVICE,
MIDI_SERVICE,
})
diff --git a/core/java/android/content/pm/RegisteredServicesCache.java b/core/java/android/content/pm/RegisteredServicesCache.java
index a386097..c2d2f65 100644
--- a/core/java/android/content/pm/RegisteredServicesCache.java
+++ b/core/java/android/content/pm/RegisteredServicesCache.java
@@ -27,6 +27,7 @@ import android.content.res.XmlResourceParser;
import android.os.Environment;
import android.os.Handler;
import android.os.UserHandle;
+import android.os.UserManager;
import android.util.AtomicFile;
import android.util.AttributeSet;
import android.util.Log;
@@ -47,9 +48,9 @@ import org.xmlpull.v1.XmlSerializer;
import java.io.File;
import java.io.FileDescriptor;
-import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.InputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collection;
@@ -74,6 +75,7 @@ import libcore.io.IoUtils;
public abstract class RegisteredServicesCache<V> {
private static final String TAG = "PackageManager";
private static final boolean DEBUG = false;
+ protected static final String REGISTERED_SERVICES_DIR = "registered_services";
public final Context mContext;
private final String mInterfaceName;
@@ -84,57 +86,67 @@ public abstract class RegisteredServicesCache<V> {
private final Object mServicesLock = new Object();
@GuardedBy("mServicesLock")
- private boolean mPersistentServicesFileDidNotExist;
- @GuardedBy("mServicesLock")
private final SparseArray<UserServices<V>> mUserServices = new SparseArray<UserServices<V>>(2);
private static class UserServices<V> {
@GuardedBy("mServicesLock")
- public final Map<V, Integer> persistentServices = Maps.newHashMap();
+ final Map<V, Integer> persistentServices = Maps.newHashMap();
+ @GuardedBy("mServicesLock")
+ Map<V, ServiceInfo<V>> services = null;
@GuardedBy("mServicesLock")
- public Map<V, ServiceInfo<V>> services = null;
+ boolean mPersistentServicesFileDidNotExist = true;
}
+ @GuardedBy("mServicesLock")
private UserServices<V> findOrCreateUserLocked(int userId) {
+ return findOrCreateUserLocked(userId, true);
+ }
+
+ @GuardedBy("mServicesLock")
+ private UserServices<V> findOrCreateUserLocked(int userId, boolean loadFromFileIfNew) {
UserServices<V> services = mUserServices.get(userId);
if (services == null) {
services = new UserServices<V>();
mUserServices.put(userId, services);
+ if (loadFromFileIfNew && mSerializerAndParser != null) {
+ // Check if user exists and try loading data from file
+ // clear existing data if there was an error during migration
+ UserInfo user = getUser(userId);
+ if (user != null) {
+ AtomicFile file = createFileForUser(user.id);
+ if (file.getBaseFile().exists()) {
+ if (DEBUG) {
+ Slog.i(TAG, String.format("Loading u%s data from %s", user.id, file));
+ }
+ InputStream is = null;
+ try {
+ is = file.openRead();
+ readPersistentServicesLocked(is);
+ } catch (Exception e) {
+ Log.w(TAG, "Error reading persistent services for user " + user.id, e);
+ } finally {
+ IoUtils.closeQuietly(is);
+ }
+ }
+ }
+ }
}
return services;
}
- /**
- * This file contains the list of known services. We would like to maintain this forever
- * so we store it as an XML file.
- */
- private final AtomicFile mPersistentServicesFile;
-
// the listener and handler are synchronized on "this" and must be updated together
private RegisteredServicesCacheListener<V> mListener;
private Handler mHandler;
public RegisteredServicesCache(Context context, String interfaceName, String metaDataName,
String attributeName, XmlSerializerAndParser<V> serializerAndParser) {
- this(context, interfaceName, metaDataName, attributeName, serializerAndParser,
- Environment.getDataDirectory());
- }
-
- @VisibleForTesting
- protected RegisteredServicesCache(Context context, String interfaceName, String metaDataName,
- String attributeName, XmlSerializerAndParser<V> serializerAndParser, File dataDir) {
mContext = context;
mInterfaceName = interfaceName;
mMetaDataName = metaDataName;
mAttributesName = attributeName;
mSerializerAndParser = serializerAndParser;
- File systemDir = new File(dataDir, "system");
- File syncDir = new File(systemDir, "registered_services");
- mPersistentServicesFile = new AtomicFile(new File(syncDir, interfaceName + ".xml"));
-
- // Load persisted services from disk
- readPersistentServicesLocked();
+ migrateIfNecessaryLocked();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
@@ -148,6 +160,11 @@ public abstract class RegisteredServicesCache<V> {
sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
mContext.registerReceiver(mExternalReceiver, sdFilter);
+
+ // Register for user-related events
+ IntentFilter userFilter = new IntentFilter();
+ sdFilter.addAction(Intent.ACTION_USER_REMOVED);
+ mContext.registerReceiver(mUserRemovedReceiver, userFilter);
}
private final void handlePackageEvent(Intent intent, int userId) {
@@ -199,6 +216,17 @@ public abstract class RegisteredServicesCache<V> {
}
};
+ private final BroadcastReceiver mUserRemovedReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
+ if (DEBUG) {
+ Slog.d(TAG, "u" + userId + " removed - cleaning up");
+ }
+ onUserRemoved(userId);
+ }
+ };
+
public void invalidateCache(int userId) {
synchronized (mServicesLock) {
final UserServices<V> user = findOrCreateUserLocked(userId);
@@ -390,7 +418,7 @@ public abstract class RegisteredServicesCache<V> {
changed = true;
user.services.put(info.type, info);
user.persistentServices.put(info.type, info.uid);
- if (!(mPersistentServicesFileDidNotExist && firstScan)) {
+ if (!(user.mPersistentServicesFileDidNotExist && firstScan)) {
notifyListener(info.type, userId, false /* removed */);
}
} else if (previousUid == info.uid) {
@@ -460,7 +488,7 @@ public abstract class RegisteredServicesCache<V> {
}
}
if (changed) {
- writePersistentServicesLocked();
+ writePersistentServicesLocked(user, userId);
}
}
}
@@ -542,89 +570,152 @@ public abstract class RegisteredServicesCache<V> {
/**
* Read all sync status back in to the initial engine state.
*/
- private void readPersistentServicesLocked() {
- mUserServices.clear();
+ private void readPersistentServicesLocked(InputStream is)
+ throws XmlPullParserException, IOException {
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(is, null);
+ int eventType = parser.getEventType();
+ while (eventType != XmlPullParser.START_TAG
+ && eventType != XmlPullParser.END_DOCUMENT) {
+ eventType = parser.next();
+ }
+ String tagName = parser.getName();
+ if ("services".equals(tagName)) {
+ eventType = parser.next();
+ do {
+ if (eventType == XmlPullParser.START_TAG && parser.getDepth() == 2) {
+ tagName = parser.getName();
+ if ("service".equals(tagName)) {
+ V service = mSerializerAndParser.createFromXml(parser);
+ if (service == null) {
+ break;
+ }
+ String uidString = parser.getAttributeValue(null, "uid");
+ final int uid = Integer.parseInt(uidString);
+ final int userId = UserHandle.getUserId(uid);
+ final UserServices<V> user = findOrCreateUserLocked(userId,
+ false /*loadFromFileIfNew*/) ;
+ user.persistentServices.put(service, uid);
+ }
+ }
+ eventType = parser.next();
+ } while (eventType != XmlPullParser.END_DOCUMENT);
+ }
+ }
+
+ private void migrateIfNecessaryLocked() {
if (mSerializerAndParser == null) {
return;
}
- FileInputStream fis = null;
- try {
- mPersistentServicesFileDidNotExist = !mPersistentServicesFile.getBaseFile().exists();
- if (mPersistentServicesFileDidNotExist) {
- return;
- }
- fis = mPersistentServicesFile.openRead();
- XmlPullParser parser = Xml.newPullParser();
- parser.setInput(fis, null);
- int eventType = parser.getEventType();
- while (eventType != XmlPullParser.START_TAG
- && eventType != XmlPullParser.END_DOCUMENT) {
- eventType = parser.next();
- }
- String tagName = parser.getName();
- if ("services".equals(tagName)) {
- eventType = parser.next();
- do {
- if (eventType == XmlPullParser.START_TAG && parser.getDepth() == 2) {
- tagName = parser.getName();
- if ("service".equals(tagName)) {
- V service = mSerializerAndParser.createFromXml(parser);
- if (service == null) {
- break;
+ File systemDir = new File(getDataDirectory(), "system");
+ File syncDir = new File(systemDir, REGISTERED_SERVICES_DIR);
+ AtomicFile oldFile = new AtomicFile(new File(syncDir, mInterfaceName + ".xml"));
+ boolean oldFileExists = oldFile.getBaseFile().exists();
+
+ if (oldFileExists) {
+ File marker = new File(syncDir, mInterfaceName + ".xml.migrated");
+ // if not migrated, perform the migration and add a marker
+ if (!marker.exists()) {
+ if (DEBUG) {
+ Slog.i(TAG, "Marker file " + marker + " does not exist - running migration");
+ }
+ InputStream is = null;
+ try {
+ is = oldFile.openRead();
+ mUserServices.clear();
+ readPersistentServicesLocked(is);
+ } catch (Exception e) {
+ Log.w(TAG, "Error reading persistent services, starting from scratch", e);
+ } finally {
+ IoUtils.closeQuietly(is);
+ }
+ try {
+ for (UserInfo user : getUsers()) {
+ UserServices<V> userServices = mUserServices.get(user.id);
+ if (userServices != null) {
+ if (DEBUG) {
+ Slog.i(TAG, "Migrating u" + user.id + " services "
+ + userServices.persistentServices);
}
- String uidString = parser.getAttributeValue(null, "uid");
- final int uid = Integer.parseInt(uidString);
- final int userId = UserHandle.getUserId(uid);
- final UserServices<V> user = findOrCreateUserLocked(userId);
- user.persistentServices.put(service, uid);
+ writePersistentServicesLocked(userServices, user.id);
}
}
- eventType = parser.next();
- } while (eventType != XmlPullParser.END_DOCUMENT);
+ marker.createNewFile();
+ } catch (Exception e) {
+ Log.w(TAG, "Migration failed", e);
+ }
+ // Migration is complete and we don't need to keep data for all users anymore,
+ // It will be loaded from a new location when requested
+ mUserServices.clear();
}
- } catch (Exception e) {
- Log.w(TAG, "Error reading persistent services, starting from scratch", e);
- } finally {
- IoUtils.closeQuietly(fis);
}
}
/**
- * Write all sync status to the sync status file.
+ * Writes services of a specified user to the file.
*/
- private void writePersistentServicesLocked() {
+ private void writePersistentServicesLocked(UserServices<V> user, int userId) {
if (mSerializerAndParser == null) {
return;
}
+ AtomicFile atomicFile = createFileForUser(userId);
FileOutputStream fos = null;
try {
- fos = mPersistentServicesFile.startWrite();
+ fos = atomicFile.startWrite();
XmlSerializer out = new FastXmlSerializer();
out.setOutput(fos, "utf-8");
out.startDocument(null, true);
out.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
out.startTag(null, "services");
- for (int i = 0; i < mUserServices.size(); i++) {
- final UserServices<V> user = mUserServices.valueAt(i);
- for (Map.Entry<V, Integer> service : user.persistentServices.entrySet()) {
- out.startTag(null, "service");
- out.attribute(null, "uid", Integer.toString(service.getValue()));
- mSerializerAndParser.writeAsXml(service.getKey(), out);
- out.endTag(null, "service");
- }
+ for (Map.Entry<V, Integer> service : user.persistentServices.entrySet()) {
+ out.startTag(null, "service");
+ out.attribute(null, "uid", Integer.toString(service.getValue()));
+ mSerializerAndParser.writeAsXml(service.getKey(), out);
+ out.endTag(null, "service");
}
out.endTag(null, "services");
out.endDocument();
- mPersistentServicesFile.finishWrite(fos);
+ atomicFile.finishWrite(fos);
} catch (IOException e1) {
Log.w(TAG, "Error writing accounts", e1);
if (fos != null) {
- mPersistentServicesFile.failWrite(fos);
+ atomicFile.failWrite(fos);
}
}
}
@VisibleForTesting
+ protected void onUserRemoved(int userId) {
+ mUserServices.remove(userId);
+ }
+
+ @VisibleForTesting
+ protected List<UserInfo> getUsers() {
+ return UserManager.get(mContext).getUsers(true);
+ }
+
+ @VisibleForTesting
+ protected UserInfo getUser(int userId) {
+ return UserManager.get(mContext).getUserInfo(userId);
+ }
+
+ private AtomicFile createFileForUser(int userId) {
+ File userDir = getUserSystemDirectory(userId);
+ File userFile = new File(userDir, REGISTERED_SERVICES_DIR + "/" + mInterfaceName + ".xml");
+ return new AtomicFile(userFile);
+ }
+
+ @VisibleForTesting
+ protected File getUserSystemDirectory(int userId) {
+ return Environment.getUserSystemDirectory(userId);
+ }
+
+ @VisibleForTesting
+ protected File getDataDirectory() {
+ return Environment.getDataDirectory();
+ }
+
+ @VisibleForTesting
protected Map<V, Integer> getPersistentServices(int userId) {
return findOrCreateUserLocked(userId).persistentServices;
}
diff --git a/core/java/android/database/DatabaseUtils.java b/core/java/android/database/DatabaseUtils.java
index c125544..e61664c 100644
--- a/core/java/android/database/DatabaseUtils.java
+++ b/core/java/android/database/DatabaseUtils.java
@@ -16,8 +16,6 @@
package android.database;
-import org.apache.commons.codec.binary.Hex;
-
import android.content.ContentValues;
import android.content.Context;
import android.content.OperationApplicationException;
@@ -416,11 +414,33 @@ public class DatabaseUtils {
* @return the collation key in hex format
*/
public static String getHexCollationKey(String name) {
- byte [] arr = getCollationKeyInBytes(name);
- char[] keys = Hex.encodeHex(arr);
+ byte[] arr = getCollationKeyInBytes(name);
+ char[] keys = encodeHex(arr);
return new String(keys, 0, getKeyLen(arr) * 2);
}
+
+ /**
+ * Used building output as Hex
+ */
+ private static final char[] DIGITS = {
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
+ };
+
+ private static char[] encodeHex(byte[] input) {
+ int l = input.length;
+ char[] out = new char[l << 1];
+
+ // two characters form the hex value.
+ for (int i = 0, j = 0; i < l; i++) {
+ out[j++] = DIGITS[(0xF0 & input[i]) >>> 4 ];
+ out[j++] = DIGITS[ 0x0F & input[i] ];
+ }
+
+ return out;
+ }
+
private static int getKeyLen(byte[] arr) {
if (arr[arr.length - 1] != 0) {
return arr.length;
diff --git a/core/java/android/hardware/Sensor.java b/core/java/android/hardware/Sensor.java
index fa5e9d2..39f4cca 100644
--- a/core/java/android/hardware/Sensor.java
+++ b/core/java/android/hardware/Sensor.java
@@ -833,4 +833,96 @@ public final class Sensor {
+ ", type=" + mType + ", maxRange=" + mMaxRange + ", resolution=" + mResolution
+ ", power=" + mPower + ", minDelay=" + mMinDelay + "}";
}
+
+ /**
+ * Sets the Type associated with the sensor.
+ * NOTE: to be used only by native bindings in SensorManager.
+ *
+ * This allows interned static strings to be used across all representations of the Sensor. If
+ * a sensor type is not referenced here, it will still be interned by the native SensorManager.
+ *
+ * @return {@code true} if the StringType was successfully set, {@code false} otherwise.
+ */
+ private boolean setType(int value) {
+ mType = value;
+ switch (mType) {
+ case TYPE_ACCELEROMETER:
+ mStringType = STRING_TYPE_ACCELEROMETER;
+ return true;
+ case TYPE_AMBIENT_TEMPERATURE:
+ mStringType = STRING_TYPE_AMBIENT_TEMPERATURE;
+ return true;
+ case TYPE_GAME_ROTATION_VECTOR:
+ mStringType = STRING_TYPE_GAME_ROTATION_VECTOR;
+ return true;
+ case TYPE_GEOMAGNETIC_ROTATION_VECTOR:
+ mStringType = STRING_TYPE_GEOMAGNETIC_ROTATION_VECTOR;
+ return true;
+ case TYPE_GLANCE_GESTURE:
+ mStringType = STRING_TYPE_GLANCE_GESTURE;
+ return true;
+ case TYPE_GRAVITY:
+ mStringType = STRING_TYPE_GRAVITY;
+ return true;
+ case TYPE_GYROSCOPE:
+ mStringType = STRING_TYPE_GYROSCOPE;
+ return true;
+ case TYPE_GYROSCOPE_UNCALIBRATED:
+ mStringType = STRING_TYPE_GYROSCOPE_UNCALIBRATED;
+ return true;
+ case TYPE_HEART_RATE:
+ mStringType = STRING_TYPE_HEART_RATE;
+ return true;
+ case TYPE_LIGHT:
+ mStringType = STRING_TYPE_LIGHT;
+ return true;
+ case TYPE_LINEAR_ACCELERATION:
+ mStringType = STRING_TYPE_LINEAR_ACCELERATION;
+ return true;
+ case TYPE_MAGNETIC_FIELD:
+ mStringType = STRING_TYPE_MAGNETIC_FIELD;
+ return true;
+ case TYPE_MAGNETIC_FIELD_UNCALIBRATED:
+ mStringType = STRING_TYPE_MAGNETIC_FIELD_UNCALIBRATED;
+ return true;
+ case TYPE_PICK_UP_GESTURE:
+ mStringType = STRING_TYPE_PICK_UP_GESTURE;
+ return true;
+ case TYPE_PRESSURE:
+ mStringType = STRING_TYPE_PRESSURE;
+ return true;
+ case TYPE_PROXIMITY:
+ mStringType = STRING_TYPE_PROXIMITY;
+ return true;
+ case TYPE_RELATIVE_HUMIDITY:
+ mStringType = STRING_TYPE_RELATIVE_HUMIDITY;
+ return true;
+ case TYPE_ROTATION_VECTOR:
+ mStringType = STRING_TYPE_ROTATION_VECTOR;
+ return true;
+ case TYPE_SIGNIFICANT_MOTION:
+ mStringType = STRING_TYPE_SIGNIFICANT_MOTION;
+ return true;
+ case TYPE_STEP_COUNTER:
+ mStringType = STRING_TYPE_STEP_COUNTER;
+ return true;
+ case TYPE_STEP_DETECTOR:
+ mStringType = STRING_TYPE_STEP_DETECTOR;
+ return true;
+ case TYPE_TILT_DETECTOR:
+ mStringType = SENSOR_STRING_TYPE_TILT_DETECTOR;
+ return true;
+ case TYPE_WAKE_GESTURE:
+ mStringType = STRING_TYPE_WAKE_GESTURE;
+ return true;
+ case TYPE_ORIENTATION:
+ mStringType = STRING_TYPE_ORIENTATION;
+ return true;
+ case TYPE_TEMPERATURE:
+ mStringType = STRING_TYPE_TEMPERATURE;
+ return true;
+ default:
+ return false;
+ }
+ }
}
diff --git a/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java b/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java
index a0a0716..615b2c8 100644
--- a/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java
+++ b/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java
@@ -269,21 +269,23 @@ public class SurfaceTextureRenderer {
throw new IllegalStateException("Illegal intermediate texture with dimension of 0");
}
- // Letterbox or pillerbox output dimensions into intermediate dimensions.
+ // Letterbox or pillar-box output dimensions into intermediate dimensions.
RectF intermediate = new RectF(/*left*/0, /*top*/0, /*right*/texWidth, /*bottom*/texHeight);
RectF output = new RectF(/*left*/0, /*top*/0, /*right*/width, /*bottom*/height);
android.graphics.Matrix boxingXform = new android.graphics.Matrix();
boxingXform.setRectToRect(output, intermediate, android.graphics.Matrix.ScaleToFit.CENTER);
boxingXform.mapRect(output);
- // Find scaling factor from pillerboxed/letterboxed output dimensions to intermediate
+ // Find scaling factor from pillar-boxed/letter-boxed output dimensions to intermediate
// buffer dimensions.
float scaleX = intermediate.width() / output.width();
float scaleY = intermediate.height() / output.height();
- // Scale opposite dimension in clip coordinates so output is letterboxed/pillerboxed into
- // the intermediate dimensions (rather than vice-versa).
- Matrix.scaleM(mMVPMatrix, /*offset*/0, /*x*/scaleY, /*y*/scaleX, /*z*/1);
+ // Intermediate texture is implicitly scaled to 'fill' the output dimensions in clip space
+ // coordinates in the shader. To avoid stretching, we need to scale the larger dimension
+ // of the intermediate buffer so that the output buffer is actually letter-boxed
+ // or pillar-boxed into the intermediate buffer after clipping.
+ Matrix.scaleM(mMVPMatrix, /*offset*/0, /*x*/scaleX, /*y*/scaleY, /*z*/1);
if (DEBUG) {
Log.d(TAG, "Scaling factors (S_x = " + scaleX + ",S_y = " + scaleY + ") used for " +
diff --git a/core/java/android/midi/MidiDeviceServer.java b/core/java/android/midi/MidiDeviceServer.java
index 7499934..4a1995f 100644
--- a/core/java/android/midi/MidiDeviceServer.java
+++ b/core/java/android/midi/MidiDeviceServer.java
@@ -254,12 +254,12 @@ public final class MidiDeviceServer implements Closeable {
return new MidiReceiver() {
@Override
- public void onPost(byte[] msg, int offset, int count, long timestamp) throws IOException {
+ public void post(byte[] msg, int offset, int count, long timestamp) throws IOException {
ArrayList<MidiInputPort> receivers = mOutputPortReceivers[portNumberF];
synchronized (receivers) {
for (int i = 0; i < receivers.size(); i++) {
// FIXME catch errors and remove dead ones
- receivers.get(i).onPost(msg, offset, count, timestamp);
+ receivers.get(i).post(msg, offset, count, timestamp);
}
}
}
diff --git a/core/java/android/midi/MidiInputPort.java b/core/java/android/midi/MidiInputPort.java
index 51c47dd..735c68a 100644
--- a/core/java/android/midi/MidiInputPort.java
+++ b/core/java/android/midi/MidiInputPort.java
@@ -50,7 +50,7 @@ public class MidiInputPort extends MidiPort implements MidiReceiver {
* @param timestamp future time to post the message (based on
* {@link java.lang.System#nanoTime}
*/
- public void onPost(byte[] msg, int offset, int count, long timestamp) throws IOException {
+ public void post(byte[] msg, int offset, int count, long timestamp) throws IOException {
assert(offset >= 0 && count >= 0 && offset + count <= msg.length);
synchronized (mBuffer) {
diff --git a/core/java/android/midi/MidiManager.java b/core/java/android/midi/MidiManager.java
index 8aa8395..3a0b064 100644
--- a/core/java/android/midi/MidiManager.java
+++ b/core/java/android/midi/MidiManager.java
@@ -66,22 +66,24 @@ public class MidiManager {
}
/**
- * Callback interface used for clients to receive MIDI device added and removed notifications
+ * Callback class used for clients to receive MIDI device added and removed notifications
*/
- public interface DeviceCallback {
+ public static class DeviceCallback {
/**
* Called to notify when a new MIDI device has been added
*
* @param device a {@link MidiDeviceInfo} for the newly added device
*/
- void onDeviceAdded(MidiDeviceInfo device);
+ void onDeviceAdded(MidiDeviceInfo device) {
+ }
/**
* Called to notify when a MIDI device has been removed
*
* @param device a {@link MidiDeviceInfo} for the removed device
*/
- void onDeviceRemoved(MidiDeviceInfo device);
+ void onDeviceRemoved(MidiDeviceInfo device) {
+ }
}
/**
diff --git a/core/java/android/midi/MidiOutputPort.java b/core/java/android/midi/MidiOutputPort.java
index 332b431..b9512fd 100644
--- a/core/java/android/midi/MidiOutputPort.java
+++ b/core/java/android/midi/MidiOutputPort.java
@@ -65,7 +65,7 @@ public class MidiOutputPort extends MidiPort implements MidiSender {
for (int i = 0; i < mReceivers.size(); i++) {
MidiReceiver receiver = mReceivers.get(i);
try {
- receiver.onPost(buffer, offset, size, timestamp);
+ receiver.post(buffer, offset, size, timestamp);
} catch (IOException e) {
Log.e(TAG, "post failed");
deadReceivers.add(receiver);
diff --git a/core/java/android/midi/MidiReceiver.java b/core/java/android/midi/MidiReceiver.java
index fdfe51a..16c9bbb 100644
--- a/core/java/android/midi/MidiReceiver.java
+++ b/core/java/android/midi/MidiReceiver.java
@@ -32,7 +32,7 @@ public interface MidiReceiver {
* The msg bytes should be copied by the receiver rather than retaining a reference
* to this parameter.
* Also, modifying the contents of the msg array parameter may result in other receivers
- * in the same application receiving incorrect values in their onPost() method.
+ * in the same application receiving incorrect values in their post() method.
*
* @param msg a byte array containing the MIDI data
* @param offset the offset of the first byte of the data in the byte array
@@ -40,5 +40,5 @@ public interface MidiReceiver {
* @param timestamp the timestamp of the message (based on {@link java.lang.System#nanoTime}
* @throws IOException
*/
- public void onPost(byte[] msg, int offset, int count, long timestamp) throws IOException;
+ public void post(byte[] msg, int offset, int count, long timestamp) throws IOException;
}
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 1a51808..808be21 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -2371,6 +2371,10 @@ public class ConnectivityManager {
* The lookup key for a {@link Network} object included with the intent after
* successfully finding a network for the applications request. Retrieve it with
* {@link android.content.Intent#getParcelableExtra(String)}.
+ * <p>
+ * Note that if you intend to invoke (@link #setProcessDefaultNetwork(Network)) or
+ * {@link Network#openConnection(java.net.URL)} then you must get a
+ * ConnectivityManager instance before doing so.
*/
public static final String EXTRA_NETWORK = "android.net.extra.NETWORK";
diff --git a/core/java/android/net/ProxyInfo.java b/core/java/android/net/ProxyInfo.java
index a3cad77..2c90909 100644
--- a/core/java/android/net/ProxyInfo.java
+++ b/core/java/android/net/ProxyInfo.java
@@ -21,8 +21,6 @@ import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
-import org.apache.http.client.HttpClient;
-
import java.net.InetSocketAddress;
import java.net.URLConnection;
import java.util.List;
@@ -31,8 +29,9 @@ import java.util.Locale;
/**
* Describes a proxy configuration.
*
- * Proxy configurations are already integrated within the Apache HTTP stack.
- * So {@link URLConnection} and {@link HttpClient} will use them automatically.
+ * Proxy configurations are already integrated within the {@code java.net} and
+ * Apache HTTP stack. So {@link URLConnection} and Apache's {@code HttpClient} will use
+ * them automatically.
*
* Other HTTP stacks will need to obtain the proxy info from
* {@link Proxy#PROXY_CHANGE_ACTION} broadcast as the extra {@link Proxy#EXTRA_PROXY_INFO}.
diff --git a/core/java/android/net/http/AndroidHttpClient.java b/core/java/android/net/http/AndroidHttpClient.java
deleted file mode 100644
index a262076..0000000
--- a/core/java/android/net/http/AndroidHttpClient.java
+++ /dev/null
@@ -1,527 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.http;
-
-import com.android.internal.http.HttpDateTime;
-
-import org.apache.http.Header;
-import org.apache.http.HttpEntity;
-import org.apache.http.HttpEntityEnclosingRequest;
-import org.apache.http.HttpException;
-import org.apache.http.HttpHost;
-import org.apache.http.HttpRequest;
-import org.apache.http.HttpRequestInterceptor;
-import org.apache.http.HttpResponse;
-import org.apache.http.client.ClientProtocolException;
-import org.apache.http.client.HttpClient;
-import org.apache.http.client.ResponseHandler;
-import org.apache.http.client.methods.HttpUriRequest;
-import org.apache.http.client.params.HttpClientParams;
-import org.apache.http.client.protocol.ClientContext;
-import org.apache.http.conn.ClientConnectionManager;
-import org.apache.http.conn.scheme.PlainSocketFactory;
-import org.apache.http.conn.scheme.Scheme;
-import org.apache.http.conn.scheme.SchemeRegistry;
-import org.apache.http.entity.AbstractHttpEntity;
-import org.apache.http.entity.ByteArrayEntity;
-import org.apache.http.impl.client.DefaultHttpClient;
-import org.apache.http.impl.client.RequestWrapper;
-import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
-import org.apache.http.params.BasicHttpParams;
-import org.apache.http.params.HttpConnectionParams;
-import org.apache.http.params.HttpParams;
-import org.apache.http.params.HttpProtocolParams;
-import org.apache.http.protocol.BasicHttpContext;
-import org.apache.http.protocol.BasicHttpProcessor;
-import org.apache.http.protocol.HttpContext;
-
-import android.content.ContentResolver;
-import android.content.Context;
-import android.net.SSLCertificateSocketFactory;
-import android.net.SSLSessionCache;
-import android.os.Looper;
-import android.util.Base64;
-import android.util.Log;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.URI;
-import java.util.zip.GZIPInputStream;
-import java.util.zip.GZIPOutputStream;
-
-/**
- * Implementation of the Apache {@link DefaultHttpClient} that is configured with
- * reasonable default settings and registered schemes for Android.
- * Don't create this directly, use the {@link #newInstance} factory method.
- *
- * <p>This client processes cookies but does not retain them by default.
- * To retain cookies, simply add a cookie store to the HttpContext:</p>
- *
- * <pre>context.setAttribute(ClientContext.COOKIE_STORE, cookieStore);</pre>
- *
- * @deprecated Please use {@link java.net.URLConnection} and friends instead.
- * The Apache HTTP client is no longer maintained and may be removed in a future
- * release. Please visit <a href="http://android-developers.blogspot.com/2011/09/androids-http-clients.html">this webpage</a>
- * for further details.
- */
-@Deprecated
-public final class AndroidHttpClient implements HttpClient {
-
- // Gzip of data shorter than this probably won't be worthwhile
- public static long DEFAULT_SYNC_MIN_GZIP_BYTES = 256;
-
- // Default connection and socket timeout of 60 seconds. Tweak to taste.
- private static final int SOCKET_OPERATION_TIMEOUT = 60 * 1000;
-
- private static final String TAG = "AndroidHttpClient";
-
- private static String[] textContentTypes = new String[] {
- "text/",
- "application/xml",
- "application/json"
- };
-
- /** Interceptor throws an exception if the executing thread is blocked */
- private static final HttpRequestInterceptor sThreadCheckInterceptor =
- new HttpRequestInterceptor() {
- public void process(HttpRequest request, HttpContext context) {
- // Prevent the HttpRequest from being sent on the main thread
- if (Looper.myLooper() != null && Looper.myLooper() == Looper.getMainLooper() ) {
- throw new RuntimeException("This thread forbids HTTP requests");
- }
- }
- };
-
- /**
- * Create a new HttpClient with reasonable defaults (which you can update).
- *
- * @param userAgent to report in your HTTP requests
- * @param context to use for caching SSL sessions (may be null for no caching)
- * @return AndroidHttpClient for you to use for all your requests.
- *
- * @deprecated Please use {@link java.net.URLConnection} and friends instead. See
- * {@link android.net.SSLCertificateSocketFactory} for SSL cache support. If you'd
- * like to set a custom useragent, please use {@link java.net.URLConnection#setRequestProperty(String, String)}
- * with {@code field} set to {@code User-Agent}.
- */
- @Deprecated
- public static AndroidHttpClient newInstance(String userAgent, Context context) {
- HttpParams params = new BasicHttpParams();
-
- // Turn off stale checking. Our connections break all the time anyway,
- // and it's not worth it to pay the penalty of checking every time.
- HttpConnectionParams.setStaleCheckingEnabled(params, false);
-
- HttpConnectionParams.setConnectionTimeout(params, SOCKET_OPERATION_TIMEOUT);
- HttpConnectionParams.setSoTimeout(params, SOCKET_OPERATION_TIMEOUT);
- HttpConnectionParams.setSocketBufferSize(params, 8192);
-
- // Don't handle redirects -- return them to the caller. Our code
- // often wants to re-POST after a redirect, which we must do ourselves.
- HttpClientParams.setRedirecting(params, false);
-
- // Use a session cache for SSL sockets
- SSLSessionCache sessionCache = context == null ? null : new SSLSessionCache(context);
-
- // Set the specified user agent and register standard protocols.
- HttpProtocolParams.setUserAgent(params, userAgent);
- SchemeRegistry schemeRegistry = new SchemeRegistry();
- schemeRegistry.register(new Scheme("http",
- PlainSocketFactory.getSocketFactory(), 80));
- schemeRegistry.register(new Scheme("https",
- SSLCertificateSocketFactory.getHttpSocketFactory(
- SOCKET_OPERATION_TIMEOUT, sessionCache), 443));
-
- ClientConnectionManager manager =
- new ThreadSafeClientConnManager(params, schemeRegistry);
-
- // We use a factory method to modify superclass initialization
- // parameters without the funny call-a-static-method dance.
- return new AndroidHttpClient(manager, params);
- }
-
- /**
- * Create a new HttpClient with reasonable defaults (which you can update).
- * @param userAgent to report in your HTTP requests.
- * @return AndroidHttpClient for you to use for all your requests.
- *
- * @deprecated Please use {@link java.net.URLConnection} and friends instead. See
- * {@link android.net.SSLCertificateSocketFactory} for SSL cache support. If you'd
- * like to set a custom useragent, please use {@link java.net.URLConnection#setRequestProperty(String, String)}
- * with {@code field} set to {@code User-Agent}.
- */
- @Deprecated
- public static AndroidHttpClient newInstance(String userAgent) {
- return newInstance(userAgent, null /* session cache */);
- }
-
- private final HttpClient delegate;
-
- private RuntimeException mLeakedException = new IllegalStateException(
- "AndroidHttpClient created and never closed");
-
- private AndroidHttpClient(ClientConnectionManager ccm, HttpParams params) {
- this.delegate = new DefaultHttpClient(ccm, params) {
- @Override
- protected BasicHttpProcessor createHttpProcessor() {
- // Add interceptor to prevent making requests from main thread.
- BasicHttpProcessor processor = super.createHttpProcessor();
- processor.addRequestInterceptor(sThreadCheckInterceptor);
- processor.addRequestInterceptor(new CurlLogger());
-
- return processor;
- }
-
- @Override
- protected HttpContext createHttpContext() {
- // Same as DefaultHttpClient.createHttpContext() minus the
- // cookie store.
- HttpContext context = new BasicHttpContext();
- context.setAttribute(
- ClientContext.AUTHSCHEME_REGISTRY,
- getAuthSchemes());
- context.setAttribute(
- ClientContext.COOKIESPEC_REGISTRY,
- getCookieSpecs());
- context.setAttribute(
- ClientContext.CREDS_PROVIDER,
- getCredentialsProvider());
- return context;
- }
- };
- }
-
- @Override
- protected void finalize() throws Throwable {
- super.finalize();
- if (mLeakedException != null) {
- Log.e(TAG, "Leak found", mLeakedException);
- mLeakedException = null;
- }
- }
-
- /**
- * Modifies a request to indicate to the server that we would like a
- * gzipped response. (Uses the "Accept-Encoding" HTTP header.)
- * @param request the request to modify
- * @see #getUngzippedContent
- */
- public static void modifyRequestToAcceptGzipResponse(HttpRequest request) {
- request.addHeader("Accept-Encoding", "gzip");
- }
-
- /**
- * Gets the input stream from a response entity. If the entity is gzipped
- * then this will get a stream over the uncompressed data.
- *
- * @param entity the entity whose content should be read
- * @return the input stream to read from
- * @throws IOException
- */
- public static InputStream getUngzippedContent(HttpEntity entity)
- throws IOException {
- InputStream responseStream = entity.getContent();
- if (responseStream == null) return responseStream;
- Header header = entity.getContentEncoding();
- if (header == null) return responseStream;
- String contentEncoding = header.getValue();
- if (contentEncoding == null) return responseStream;
- if (contentEncoding.contains("gzip")) responseStream
- = new GZIPInputStream(responseStream);
- return responseStream;
- }
-
- /**
- * Release resources associated with this client. You must call this,
- * or significant resources (sockets and memory) may be leaked.
- */
- public void close() {
- if (mLeakedException != null) {
- getConnectionManager().shutdown();
- mLeakedException = null;
- }
- }
-
- public HttpParams getParams() {
- return delegate.getParams();
- }
-
- public ClientConnectionManager getConnectionManager() {
- return delegate.getConnectionManager();
- }
-
- public HttpResponse execute(HttpUriRequest request) throws IOException {
- return delegate.execute(request);
- }
-
- public HttpResponse execute(HttpUriRequest request, HttpContext context)
- throws IOException {
- return delegate.execute(request, context);
- }
-
- public HttpResponse execute(HttpHost target, HttpRequest request)
- throws IOException {
- return delegate.execute(target, request);
- }
-
- public HttpResponse execute(HttpHost target, HttpRequest request,
- HttpContext context) throws IOException {
- return delegate.execute(target, request, context);
- }
-
- public <T> T execute(HttpUriRequest request,
- ResponseHandler<? extends T> responseHandler)
- throws IOException, ClientProtocolException {
- return delegate.execute(request, responseHandler);
- }
-
- public <T> T execute(HttpUriRequest request,
- ResponseHandler<? extends T> responseHandler, HttpContext context)
- throws IOException, ClientProtocolException {
- return delegate.execute(request, responseHandler, context);
- }
-
- public <T> T execute(HttpHost target, HttpRequest request,
- ResponseHandler<? extends T> responseHandler) throws IOException,
- ClientProtocolException {
- return delegate.execute(target, request, responseHandler);
- }
-
- public <T> T execute(HttpHost target, HttpRequest request,
- ResponseHandler<? extends T> responseHandler, HttpContext context)
- throws IOException, ClientProtocolException {
- return delegate.execute(target, request, responseHandler, context);
- }
-
- /**
- * Compress data to send to server.
- * Creates a Http Entity holding the gzipped data.
- * The data will not be compressed if it is too short.
- * @param data The bytes to compress
- * @return Entity holding the data
- */
- public static AbstractHttpEntity getCompressedEntity(byte data[], ContentResolver resolver)
- throws IOException {
- AbstractHttpEntity entity;
- if (data.length < getMinGzipSize(resolver)) {
- entity = new ByteArrayEntity(data);
- } else {
- ByteArrayOutputStream arr = new ByteArrayOutputStream();
- OutputStream zipper = new GZIPOutputStream(arr);
- zipper.write(data);
- zipper.close();
- entity = new ByteArrayEntity(arr.toByteArray());
- entity.setContentEncoding("gzip");
- }
- return entity;
- }
-
- /**
- * Retrieves the minimum size for compressing data.
- * Shorter data will not be compressed.
- */
- public static long getMinGzipSize(ContentResolver resolver) {
- return DEFAULT_SYNC_MIN_GZIP_BYTES; // For now, this is just a constant.
- }
-
- /* cURL logging support. */
-
- /**
- * Logging tag and level.
- */
- private static class LoggingConfiguration {
-
- private final String tag;
- private final int level;
-
- private LoggingConfiguration(String tag, int level) {
- this.tag = tag;
- this.level = level;
- }
-
- /**
- * Returns true if logging is turned on for this configuration.
- */
- private boolean isLoggable() {
- return Log.isLoggable(tag, level);
- }
-
- /**
- * Prints a message using this configuration.
- */
- private void println(String message) {
- Log.println(level, tag, message);
- }
- }
-
- /** cURL logging configuration. */
- private volatile LoggingConfiguration curlConfiguration;
-
- /**
- * Enables cURL request logging for this client.
- *
- * @param name to log messages with
- * @param level at which to log messages (see {@link android.util.Log})
- */
- public void enableCurlLogging(String name, int level) {
- if (name == null) {
- throw new NullPointerException("name");
- }
- if (level < Log.VERBOSE || level > Log.ASSERT) {
- throw new IllegalArgumentException("Level is out of range ["
- + Log.VERBOSE + ".." + Log.ASSERT + "]");
- }
-
- curlConfiguration = new LoggingConfiguration(name, level);
- }
-
- /**
- * Disables cURL logging for this client.
- */
- public void disableCurlLogging() {
- curlConfiguration = null;
- }
-
- /**
- * Logs cURL commands equivalent to requests.
- */
- private class CurlLogger implements HttpRequestInterceptor {
- public void process(HttpRequest request, HttpContext context)
- throws HttpException, IOException {
- LoggingConfiguration configuration = curlConfiguration;
- if (configuration != null
- && configuration.isLoggable()
- && request instanceof HttpUriRequest) {
- // Never print auth token -- we used to check ro.secure=0 to
- // enable that, but can't do that in unbundled code.
- configuration.println(toCurl((HttpUriRequest) request, false));
- }
- }
- }
-
- /**
- * Generates a cURL command equivalent to the given request.
- */
- private static String toCurl(HttpUriRequest request, boolean logAuthToken) throws IOException {
- StringBuilder builder = new StringBuilder();
-
- builder.append("curl ");
-
- // add in the method
- builder.append("-X ");
- builder.append(request.getMethod());
- builder.append(" ");
-
- for (Header header: request.getAllHeaders()) {
- if (!logAuthToken
- && (header.getName().equals("Authorization") ||
- header.getName().equals("Cookie"))) {
- continue;
- }
- builder.append("--header \"");
- builder.append(header.toString().trim());
- builder.append("\" ");
- }
-
- URI uri = request.getURI();
-
- // If this is a wrapped request, use the URI from the original
- // request instead. getURI() on the wrapper seems to return a
- // relative URI. We want an absolute URI.
- if (request instanceof RequestWrapper) {
- HttpRequest original = ((RequestWrapper) request).getOriginal();
- if (original instanceof HttpUriRequest) {
- uri = ((HttpUriRequest) original).getURI();
- }
- }
-
- builder.append("\"");
- builder.append(uri);
- builder.append("\"");
-
- if (request instanceof HttpEntityEnclosingRequest) {
- HttpEntityEnclosingRequest entityRequest =
- (HttpEntityEnclosingRequest) request;
- HttpEntity entity = entityRequest.getEntity();
- if (entity != null && entity.isRepeatable()) {
- if (entity.getContentLength() < 1024) {
- ByteArrayOutputStream stream = new ByteArrayOutputStream();
- entity.writeTo(stream);
-
- if (isBinaryContent(request)) {
- String base64 = Base64.encodeToString(stream.toByteArray(), Base64.NO_WRAP);
- builder.insert(0, "echo '" + base64 + "' | base64 -d > /tmp/$$.bin; ");
- builder.append(" --data-binary @/tmp/$$.bin");
- } else {
- String entityString = stream.toString();
- builder.append(" --data-ascii \"")
- .append(entityString)
- .append("\"");
- }
- } else {
- builder.append(" [TOO MUCH DATA TO INCLUDE]");
- }
- }
- }
-
- return builder.toString();
- }
-
- private static boolean isBinaryContent(HttpUriRequest request) {
- Header[] headers;
- headers = request.getHeaders(Headers.CONTENT_ENCODING);
- if (headers != null) {
- for (Header header : headers) {
- if ("gzip".equalsIgnoreCase(header.getValue())) {
- return true;
- }
- }
- }
-
- headers = request.getHeaders(Headers.CONTENT_TYPE);
- if (headers != null) {
- for (Header header : headers) {
- for (String contentType : textContentTypes) {
- if (header.getValue().startsWith(contentType)) {
- return false;
- }
- }
- }
- }
- return true;
- }
-
- /**
- * Returns the date of the given HTTP date string. This method can identify
- * and parse the date formats emitted by common HTTP servers, such as
- * <a href="http://www.ietf.org/rfc/rfc0822.txt">RFC 822</a>,
- * <a href="http://www.ietf.org/rfc/rfc0850.txt">RFC 850</a>,
- * <a href="http://www.ietf.org/rfc/rfc1036.txt">RFC 1036</a>,
- * <a href="http://www.ietf.org/rfc/rfc1123.txt">RFC 1123</a> and
- * <a href="http://www.opengroup.org/onlinepubs/007908799/xsh/asctime.html">ANSI
- * C's asctime()</a>.
- *
- * @return the number of milliseconds since Jan. 1, 1970, midnight GMT.
- * @throws IllegalArgumentException if {@code dateString} is not a date or
- * of an unsupported format.
- */
- public static long parseDate(String dateString) {
- return HttpDateTime.parse(dateString);
- }
-}
diff --git a/core/java/android/net/http/AndroidHttpClientConnection.java b/core/java/android/net/http/AndroidHttpClientConnection.java
deleted file mode 100644
index 6d48fce..0000000
--- a/core/java/android/net/http/AndroidHttpClientConnection.java
+++ /dev/null
@@ -1,460 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.http;
-
-import org.apache.http.HttpConnection;
-import org.apache.http.HttpClientConnection;
-import org.apache.http.HttpConnectionMetrics;
-import org.apache.http.HttpEntity;
-import org.apache.http.HttpEntityEnclosingRequest;
-import org.apache.http.HttpException;
-import org.apache.http.HttpInetConnection;
-import org.apache.http.HttpRequest;
-import org.apache.http.HttpResponse;
-import org.apache.http.NoHttpResponseException;
-import org.apache.http.StatusLine;
-import org.apache.http.entity.BasicHttpEntity;
-import org.apache.http.entity.ContentLengthStrategy;
-import org.apache.http.impl.HttpConnectionMetricsImpl;
-import org.apache.http.impl.entity.EntitySerializer;
-import org.apache.http.impl.entity.StrictContentLengthStrategy;
-import org.apache.http.impl.io.ChunkedInputStream;
-import org.apache.http.impl.io.ContentLengthInputStream;
-import org.apache.http.impl.io.HttpRequestWriter;
-import org.apache.http.impl.io.IdentityInputStream;
-import org.apache.http.impl.io.SocketInputBuffer;
-import org.apache.http.impl.io.SocketOutputBuffer;
-import org.apache.http.io.HttpMessageWriter;
-import org.apache.http.io.SessionInputBuffer;
-import org.apache.http.io.SessionOutputBuffer;
-import org.apache.http.message.BasicLineParser;
-import org.apache.http.message.ParserCursor;
-import org.apache.http.params.CoreConnectionPNames;
-import org.apache.http.params.HttpConnectionParams;
-import org.apache.http.params.HttpParams;
-import org.apache.http.ParseException;
-import org.apache.http.util.CharArrayBuffer;
-
-import java.io.IOException;
-import java.net.InetAddress;
-import java.net.Socket;
-import java.net.SocketException;
-
-/**
- * A alternate class for (@link DefaultHttpClientConnection).
- * It has better performance than DefaultHttpClientConnection
- *
- * {@hide}
- */
-public class AndroidHttpClientConnection
- implements HttpInetConnection, HttpConnection {
-
- private SessionInputBuffer inbuffer = null;
- private SessionOutputBuffer outbuffer = null;
- private int maxHeaderCount;
- // store CoreConnectionPNames.MAX_LINE_LENGTH for performance
- private int maxLineLength;
-
- private final EntitySerializer entityserializer;
-
- private HttpMessageWriter requestWriter = null;
- private HttpConnectionMetricsImpl metrics = null;
- private volatile boolean open;
- private Socket socket = null;
-
- public AndroidHttpClientConnection() {
- this.entityserializer = new EntitySerializer(
- new StrictContentLengthStrategy());
- }
-
- /**
- * Bind socket and set HttpParams to AndroidHttpClientConnection
- * @param socket outgoing socket
- * @param params HttpParams
- * @throws IOException
- */
- public void bind(
- final Socket socket,
- final HttpParams params) throws IOException {
- if (socket == null) {
- throw new IllegalArgumentException("Socket may not be null");
- }
- if (params == null) {
- throw new IllegalArgumentException("HTTP parameters may not be null");
- }
- assertNotOpen();
- socket.setTcpNoDelay(HttpConnectionParams.getTcpNoDelay(params));
- socket.setSoTimeout(HttpConnectionParams.getSoTimeout(params));
-
- int linger = HttpConnectionParams.getLinger(params);
- if (linger >= 0) {
- socket.setSoLinger(linger > 0, linger);
- }
- this.socket = socket;
-
- int buffersize = HttpConnectionParams.getSocketBufferSize(params);
- this.inbuffer = new SocketInputBuffer(socket, buffersize, params);
- this.outbuffer = new SocketOutputBuffer(socket, buffersize, params);
-
- maxHeaderCount = params.getIntParameter(
- CoreConnectionPNames.MAX_HEADER_COUNT, -1);
- maxLineLength = params.getIntParameter(
- CoreConnectionPNames.MAX_LINE_LENGTH, -1);
-
- this.requestWriter = new HttpRequestWriter(outbuffer, null, params);
-
- this.metrics = new HttpConnectionMetricsImpl(
- inbuffer.getMetrics(),
- outbuffer.getMetrics());
-
- this.open = true;
- }
-
- @Override
- public String toString() {
- StringBuilder buffer = new StringBuilder();
- buffer.append(getClass().getSimpleName()).append("[");
- if (isOpen()) {
- buffer.append(getRemotePort());
- } else {
- buffer.append("closed");
- }
- buffer.append("]");
- return buffer.toString();
- }
-
-
- private void assertNotOpen() {
- if (this.open) {
- throw new IllegalStateException("Connection is already open");
- }
- }
-
- private void assertOpen() {
- if (!this.open) {
- throw new IllegalStateException("Connection is not open");
- }
- }
-
- public boolean isOpen() {
- // to make this method useful, we want to check if the socket is connected
- return (this.open && this.socket != null && this.socket.isConnected());
- }
-
- public InetAddress getLocalAddress() {
- if (this.socket != null) {
- return this.socket.getLocalAddress();
- } else {
- return null;
- }
- }
-
- public int getLocalPort() {
- if (this.socket != null) {
- return this.socket.getLocalPort();
- } else {
- return -1;
- }
- }
-
- public InetAddress getRemoteAddress() {
- if (this.socket != null) {
- return this.socket.getInetAddress();
- } else {
- return null;
- }
- }
-
- public int getRemotePort() {
- if (this.socket != null) {
- return this.socket.getPort();
- } else {
- return -1;
- }
- }
-
- public void setSocketTimeout(int timeout) {
- assertOpen();
- if (this.socket != null) {
- try {
- this.socket.setSoTimeout(timeout);
- } catch (SocketException ignore) {
- // It is not quite clear from the original documentation if there are any
- // other legitimate cases for a socket exception to be thrown when setting
- // SO_TIMEOUT besides the socket being already closed
- }
- }
- }
-
- public int getSocketTimeout() {
- if (this.socket != null) {
- try {
- return this.socket.getSoTimeout();
- } catch (SocketException ignore) {
- return -1;
- }
- } else {
- return -1;
- }
- }
-
- public void shutdown() throws IOException {
- this.open = false;
- Socket tmpsocket = this.socket;
- if (tmpsocket != null) {
- tmpsocket.close();
- }
- }
-
- public void close() throws IOException {
- if (!this.open) {
- return;
- }
- this.open = false;
- doFlush();
- try {
- try {
- this.socket.shutdownOutput();
- } catch (IOException ignore) {
- }
- try {
- this.socket.shutdownInput();
- } catch (IOException ignore) {
- }
- } catch (UnsupportedOperationException ignore) {
- // if one isn't supported, the other one isn't either
- }
- this.socket.close();
- }
-
- /**
- * Sends the request line and all headers over the connection.
- * @param request the request whose headers to send.
- * @throws HttpException
- * @throws IOException
- */
- public void sendRequestHeader(final HttpRequest request)
- throws HttpException, IOException {
- if (request == null) {
- throw new IllegalArgumentException("HTTP request may not be null");
- }
- assertOpen();
- this.requestWriter.write(request);
- this.metrics.incrementRequestCount();
- }
-
- /**
- * Sends the request entity over the connection.
- * @param request the request whose entity to send.
- * @throws HttpException
- * @throws IOException
- */
- public void sendRequestEntity(final HttpEntityEnclosingRequest request)
- throws HttpException, IOException {
- if (request == null) {
- throw new IllegalArgumentException("HTTP request may not be null");
- }
- assertOpen();
- if (request.getEntity() == null) {
- return;
- }
- this.entityserializer.serialize(
- this.outbuffer,
- request,
- request.getEntity());
- }
-
- protected void doFlush() throws IOException {
- this.outbuffer.flush();
- }
-
- public void flush() throws IOException {
- assertOpen();
- doFlush();
- }
-
- /**
- * Parses the response headers and adds them to the
- * given {@code headers} object, and returns the response StatusLine
- * @param headers store parsed header to headers.
- * @throws IOException
- * @return StatusLine
- * @see HttpClientConnection#receiveResponseHeader()
- */
- public StatusLine parseResponseHeader(Headers headers)
- throws IOException, ParseException {
- assertOpen();
-
- CharArrayBuffer current = new CharArrayBuffer(64);
-
- if (inbuffer.readLine(current) == -1) {
- throw new NoHttpResponseException("The target server failed to respond");
- }
-
- // Create the status line from the status string
- StatusLine statusline = BasicLineParser.DEFAULT.parseStatusLine(
- current, new ParserCursor(0, current.length()));
-
- if (HttpLog.LOGV) HttpLog.v("read: " + statusline);
- int statusCode = statusline.getStatusCode();
-
- // Parse header body
- CharArrayBuffer previous = null;
- int headerNumber = 0;
- while(true) {
- if (current == null) {
- current = new CharArrayBuffer(64);
- } else {
- // This must be he buffer used to parse the status
- current.clear();
- }
- int l = inbuffer.readLine(current);
- if (l == -1 || current.length() < 1) {
- break;
- }
- // Parse the header name and value
- // Check for folded headers first
- // Detect LWS-char see HTTP/1.0 or HTTP/1.1 Section 2.2
- // discussion on folded headers
- char first = current.charAt(0);
- if ((first == ' ' || first == '\t') && previous != null) {
- // we have continuation folded header
- // so append value
- int start = 0;
- int length = current.length();
- while (start < length) {
- char ch = current.charAt(start);
- if (ch != ' ' && ch != '\t') {
- break;
- }
- start++;
- }
- if (maxLineLength > 0 &&
- previous.length() + 1 + current.length() - start >
- maxLineLength) {
- throw new IOException("Maximum line length limit exceeded");
- }
- previous.append(' ');
- previous.append(current, start, current.length() - start);
- } else {
- if (previous != null) {
- headers.parseHeader(previous);
- }
- headerNumber++;
- previous = current;
- current = null;
- }
- if (maxHeaderCount > 0 && headerNumber >= maxHeaderCount) {
- throw new IOException("Maximum header count exceeded");
- }
- }
-
- if (previous != null) {
- headers.parseHeader(previous);
- }
-
- if (statusCode >= 200) {
- this.metrics.incrementResponseCount();
- }
- return statusline;
- }
-
- /**
- * Return the next response entity.
- * @param headers contains values for parsing entity
- * @see HttpClientConnection#receiveResponseEntity(HttpResponse response)
- */
- public HttpEntity receiveResponseEntity(final Headers headers) {
- assertOpen();
- BasicHttpEntity entity = new BasicHttpEntity();
-
- long len = determineLength(headers);
- if (len == ContentLengthStrategy.CHUNKED) {
- entity.setChunked(true);
- entity.setContentLength(-1);
- entity.setContent(new ChunkedInputStream(inbuffer));
- } else if (len == ContentLengthStrategy.IDENTITY) {
- entity.setChunked(false);
- entity.setContentLength(-1);
- entity.setContent(new IdentityInputStream(inbuffer));
- } else {
- entity.setChunked(false);
- entity.setContentLength(len);
- entity.setContent(new ContentLengthInputStream(inbuffer, len));
- }
-
- String contentTypeHeader = headers.getContentType();
- if (contentTypeHeader != null) {
- entity.setContentType(contentTypeHeader);
- }
- String contentEncodingHeader = headers.getContentEncoding();
- if (contentEncodingHeader != null) {
- entity.setContentEncoding(contentEncodingHeader);
- }
-
- return entity;
- }
-
- private long determineLength(final Headers headers) {
- long transferEncoding = headers.getTransferEncoding();
- // We use Transfer-Encoding if present and ignore Content-Length.
- // RFC2616, 4.4 item number 3
- if (transferEncoding < Headers.NO_TRANSFER_ENCODING) {
- return transferEncoding;
- } else {
- long contentlen = headers.getContentLength();
- if (contentlen > Headers.NO_CONTENT_LENGTH) {
- return contentlen;
- } else {
- return ContentLengthStrategy.IDENTITY;
- }
- }
- }
-
- /**
- * Checks whether this connection has gone down.
- * Network connections may get closed during some time of inactivity
- * for several reasons. The next time a read is attempted on such a
- * connection it will throw an IOException.
- * This method tries to alleviate this inconvenience by trying to
- * find out if a connection is still usable. Implementations may do
- * that by attempting a read with a very small timeout. Thus this
- * method may block for a small amount of time before returning a result.
- * It is therefore an <i>expensive</i> operation.
- *
- * @return <code>true</code> if attempts to use this connection are
- * likely to succeed, or <code>false</code> if they are likely
- * to fail and this connection should be closed
- */
- public boolean isStale() {
- assertOpen();
- try {
- this.inbuffer.isDataAvailable(1);
- return false;
- } catch (IOException ex) {
- return true;
- }
- }
-
- /**
- * Returns a collection of connection metrcis
- * @return HttpConnectionMetrics
- */
- public HttpConnectionMetrics getMetrics() {
- return this.metrics;
- }
-}
diff --git a/core/java/android/net/http/CertificateChainValidator.java b/core/java/android/net/http/CertificateChainValidator.java
deleted file mode 100644
index bf3fe02..0000000
--- a/core/java/android/net/http/CertificateChainValidator.java
+++ /dev/null
@@ -1,279 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.http;
-
-import com.android.org.conscrypt.SSLParametersImpl;
-import com.android.org.conscrypt.TrustManagerImpl;
-
-import android.util.Slog;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.lang.reflect.Method;
-import java.security.GeneralSecurityException;
-import java.security.KeyStore;
-import java.security.KeyStoreException;
-import java.security.NoSuchAlgorithmException;
-import java.security.cert.Certificate;
-import java.security.cert.CertificateException;
-import java.security.cert.CertificateFactory;
-import java.security.cert.X509Certificate;
-
-import javax.net.ssl.HostnameVerifier;
-import javax.net.ssl.HttpsURLConnection;
-import javax.net.ssl.SSLHandshakeException;
-import javax.net.ssl.SSLSession;
-import javax.net.ssl.SSLSocket;
-import javax.net.ssl.TrustManager;
-import javax.net.ssl.TrustManagerFactory;
-import javax.net.ssl.X509TrustManager;
-
-/**
- * Class responsible for all server certificate validation functionality
- *
- * {@hide}
- */
-public class CertificateChainValidator {
- private static final String TAG = "CertificateChainValidator";
-
- private static class NoPreloadHolder {
- /**
- * The singleton instance of the certificate chain validator.
- */
- private static final CertificateChainValidator sInstance = new CertificateChainValidator();
-
- /**
- * The singleton instance of the hostname verifier.
- */
- private static final HostnameVerifier sVerifier = HttpsURLConnection
- .getDefaultHostnameVerifier();
- }
-
- private X509TrustManager mTrustManager;
-
- /**
- * @return The singleton instance of the certificates chain validator
- */
- public static CertificateChainValidator getInstance() {
- return NoPreloadHolder.sInstance;
- }
-
- /**
- * Creates a new certificate chain validator. This is a private constructor.
- * If you need a Certificate chain validator, call getInstance().
- */
- private CertificateChainValidator() {
- try {
- TrustManagerFactory tmf = TrustManagerFactory.getInstance("X.509");
- tmf.init((KeyStore) null);
- for (TrustManager tm : tmf.getTrustManagers()) {
- if (tm instanceof X509TrustManager) {
- mTrustManager = (X509TrustManager) tm;
- }
- }
- } catch (NoSuchAlgorithmException e) {
- throw new RuntimeException("X.509 TrustManagerFactory must be available", e);
- } catch (KeyStoreException e) {
- throw new RuntimeException("X.509 TrustManagerFactory cannot be initialized", e);
- }
-
- if (mTrustManager == null) {
- throw new RuntimeException(
- "None of the X.509 TrustManagers are X509TrustManager");
- }
- }
-
- /**
- * Performs the handshake and server certificates validation
- * Notice a new chain will be rebuilt by tracing the issuer and subject
- * before calling checkServerTrusted().
- * And if the last traced certificate is self issued and it is expired, it
- * will be dropped.
- * @param sslSocket The secure connection socket
- * @param domain The website domain
- * @return An SSL error object if there is an error and null otherwise
- */
- public SslError doHandshakeAndValidateServerCertificates(
- HttpsConnection connection, SSLSocket sslSocket, String domain)
- throws IOException {
- // get a valid SSLSession, close the socket if we fail
- SSLSession sslSession = sslSocket.getSession();
- if (!sslSession.isValid()) {
- closeSocketThrowException(sslSocket, "failed to perform SSL handshake");
- }
-
- // retrieve the chain of the server peer certificates
- Certificate[] peerCertificates =
- sslSocket.getSession().getPeerCertificates();
-
- if (peerCertificates == null || peerCertificates.length == 0) {
- closeSocketThrowException(
- sslSocket, "failed to retrieve peer certificates");
- } else {
- // update the SSL certificate associated with the connection
- if (connection != null) {
- if (peerCertificates[0] != null) {
- connection.setCertificate(
- new SslCertificate((X509Certificate)peerCertificates[0]));
- }
- }
- }
-
- return verifyServerDomainAndCertificates((X509Certificate[]) peerCertificates, domain, "RSA");
- }
-
- /**
- * Similar to doHandshakeAndValidateServerCertificates but exposed to JNI for use
- * by Chromium HTTPS stack to validate the cert chain.
- * @param certChain The bytes for certificates in ASN.1 DER encoded certificates format.
- * @param domain The full website hostname and domain
- * @param authType The authentication type for the cert chain
- * @return An SSL error object if there is an error and null otherwise
- */
- public static SslError verifyServerCertificates(
- byte[][] certChain, String domain, String authType)
- throws IOException {
-
- if (certChain == null || certChain.length == 0) {
- throw new IllegalArgumentException("bad certificate chain");
- }
-
- X509Certificate[] serverCertificates = new X509Certificate[certChain.length];
-
- try {
- CertificateFactory cf = CertificateFactory.getInstance("X.509");
- for (int i = 0; i < certChain.length; ++i) {
- serverCertificates[i] = (X509Certificate) cf.generateCertificate(
- new ByteArrayInputStream(certChain[i]));
- }
- } catch (CertificateException e) {
- throw new IOException("can't read certificate", e);
- }
-
- return verifyServerDomainAndCertificates(serverCertificates, domain, authType);
- }
-
- /**
- * Handles updates to credential storage.
- */
- public static void handleTrustStorageUpdate() {
- TrustManagerFactory tmf;
- try {
- tmf = TrustManagerFactory.getInstance("X.509");
- tmf.init((KeyStore) null);
- } catch (NoSuchAlgorithmException e) {
- Slog.w(TAG, "Couldn't find default X.509 TrustManagerFactory");
- return;
- } catch (KeyStoreException e) {
- Slog.w(TAG, "Couldn't initialize default X.509 TrustManagerFactory", e);
- return;
- }
-
- TrustManager[] tms = tmf.getTrustManagers();
- boolean sentUpdate = false;
- for (TrustManager tm : tms) {
- try {
- Method updateMethod = tm.getClass().getDeclaredMethod("handleTrustStorageUpdate");
- updateMethod.setAccessible(true);
- updateMethod.invoke(tm);
- sentUpdate = true;
- } catch (Exception e) {
- }
- }
- if (!sentUpdate) {
- Slog.w(TAG, "Didn't find a TrustManager to handle CA list update");
- }
- }
-
- /**
- * Common code of doHandshakeAndValidateServerCertificates and verifyServerCertificates.
- * Calls DomainNamevalidator to verify the domain, and TrustManager to verify the certs.
- * @param chain the cert chain in X509 cert format.
- * @param domain The full website hostname and domain
- * @param authType The authentication type for the cert chain
- * @return An SSL error object if there is an error and null otherwise
- */
- private static SslError verifyServerDomainAndCertificates(
- X509Certificate[] chain, String domain, String authType)
- throws IOException {
- // check if the first certificate in the chain is for this site
- X509Certificate currCertificate = chain[0];
- if (currCertificate == null) {
- throw new IllegalArgumentException("certificate for this site is null");
- }
-
- boolean valid = domain != null
- && !domain.isEmpty()
- && NoPreloadHolder.sVerifier.verify(domain,
- new DelegatingSSLSession.CertificateWrap(currCertificate));
- if (!valid) {
- if (HttpLog.LOGV) {
- HttpLog.v("certificate not for this host: " + domain);
- }
- return new SslError(SslError.SSL_IDMISMATCH, currCertificate);
- }
-
- try {
- X509TrustManager x509TrustManager = SSLParametersImpl.getDefaultX509TrustManager();
- if (x509TrustManager instanceof TrustManagerImpl) {
- TrustManagerImpl trustManager = (TrustManagerImpl) x509TrustManager;
- trustManager.checkServerTrusted(chain, authType, domain);
- } else {
- x509TrustManager.checkServerTrusted(chain, authType);
- }
- return null; // No errors.
- } catch (GeneralSecurityException e) {
- if (HttpLog.LOGV) {
- HttpLog.v("failed to validate the certificate chain, error: " +
- e.getMessage());
- }
- return new SslError(SslError.SSL_UNTRUSTED, currCertificate);
- }
- }
-
- /**
- * Returns the platform default {@link X509TrustManager}.
- */
- private X509TrustManager getTrustManager() {
- return mTrustManager;
- }
-
- private void closeSocketThrowException(
- SSLSocket socket, String errorMessage, String defaultErrorMessage)
- throws IOException {
- closeSocketThrowException(
- socket, errorMessage != null ? errorMessage : defaultErrorMessage);
- }
-
- private void closeSocketThrowException(SSLSocket socket,
- String errorMessage) throws IOException {
- if (HttpLog.LOGV) {
- HttpLog.v("validation error: " + errorMessage);
- }
-
- if (socket != null) {
- SSLSession session = socket.getSession();
- if (session != null) {
- session.invalidate();
- }
-
- socket.close();
- }
-
- throw new SSLHandshakeException(errorMessage);
- }
-}
diff --git a/core/java/android/net/http/Connection.java b/core/java/android/net/http/Connection.java
deleted file mode 100644
index 831bd0e..0000000
--- a/core/java/android/net/http/Connection.java
+++ /dev/null
@@ -1,575 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.http;
-
-import android.content.Context;
-import android.os.SystemClock;
-
-import java.io.IOException;
-import java.net.UnknownHostException;
-import java.util.LinkedList;
-
-import javax.net.ssl.SSLHandshakeException;
-
-import org.apache.http.ConnectionReuseStrategy;
-import org.apache.http.HttpEntity;
-import org.apache.http.HttpException;
-import org.apache.http.HttpHost;
-import org.apache.http.HttpVersion;
-import org.apache.http.ParseException;
-import org.apache.http.ProtocolVersion;
-import org.apache.http.protocol.ExecutionContext;
-import org.apache.http.protocol.HttpContext;
-import org.apache.http.protocol.BasicHttpContext;
-
-/**
- * {@hide}
- */
-abstract class Connection {
-
- /**
- * Allow a TCP connection 60 idle seconds before erroring out
- */
- static final int SOCKET_TIMEOUT = 60000;
-
- private static final int SEND = 0;
- private static final int READ = 1;
- private static final int DRAIN = 2;
- private static final int DONE = 3;
- private static final String[] states = {"SEND", "READ", "DRAIN", "DONE"};
-
- Context mContext;
-
- /** The low level connection */
- protected AndroidHttpClientConnection mHttpClientConnection = null;
-
- /**
- * The server SSL certificate associated with this connection
- * (null if the connection is not secure)
- * It would be nice to store the whole certificate chain, but
- * we want to keep things as light-weight as possible
- */
- protected SslCertificate mCertificate = null;
-
- /**
- * The host this connection is connected to. If using proxy,
- * this is set to the proxy address
- */
- HttpHost mHost;
-
- /** true if the connection can be reused for sending more requests */
- private boolean mCanPersist;
-
- /** context required by ConnectionReuseStrategy. */
- private HttpContext mHttpContext;
-
- /** set when cancelled */
- private static int STATE_NORMAL = 0;
- private static int STATE_CANCEL_REQUESTED = 1;
- private int mActive = STATE_NORMAL;
-
- /** The number of times to try to re-connect (if connect fails). */
- private final static int RETRY_REQUEST_LIMIT = 2;
-
- private static final int MIN_PIPE = 2;
- private static final int MAX_PIPE = 3;
-
- /**
- * Doesn't seem to exist anymore in the new HTTP client, so copied here.
- */
- private static final String HTTP_CONNECTION = "http.connection";
-
- RequestFeeder mRequestFeeder;
-
- /**
- * Buffer for feeding response blocks to webkit. One block per
- * connection reduces memory churn.
- */
- private byte[] mBuf;
-
- protected Connection(Context context, HttpHost host,
- RequestFeeder requestFeeder) {
- mContext = context;
- mHost = host;
- mRequestFeeder = requestFeeder;
-
- mCanPersist = false;
- mHttpContext = new BasicHttpContext(null);
- }
-
- HttpHost getHost() {
- return mHost;
- }
-
- /**
- * connection factory: returns an HTTP or HTTPS connection as
- * necessary
- */
- static Connection getConnection(
- Context context, HttpHost host, HttpHost proxy,
- RequestFeeder requestFeeder) {
-
- if (host.getSchemeName().equals("http")) {
- return new HttpConnection(context, host, requestFeeder);
- }
-
- // Otherwise, default to https
- return new HttpsConnection(context, host, proxy, requestFeeder);
- }
-
- /**
- * @return The server SSL certificate associated with this
- * connection (null if the connection is not secure)
- */
- /* package */ SslCertificate getCertificate() {
- return mCertificate;
- }
-
- /**
- * Close current network connection
- * Note: this runs in non-network thread
- */
- void cancel() {
- mActive = STATE_CANCEL_REQUESTED;
- closeConnection();
- if (HttpLog.LOGV) HttpLog.v(
- "Connection.cancel(): connection closed " + mHost);
- }
-
- /**
- * Process requests in queue
- * pipelines requests
- */
- void processRequests(Request firstRequest) {
- Request req = null;
- boolean empty;
- int error = EventHandler.OK;
- Exception exception = null;
-
- LinkedList<Request> pipe = new LinkedList<Request>();
-
- int minPipe = MIN_PIPE, maxPipe = MAX_PIPE;
- int state = SEND;
-
- while (state != DONE) {
- if (HttpLog.LOGV) HttpLog.v(
- states[state] + " pipe " + pipe.size());
-
- /* If a request was cancelled, give other cancel requests
- some time to go through so we don't uselessly restart
- connections */
- if (mActive == STATE_CANCEL_REQUESTED) {
- try {
- Thread.sleep(100);
- } catch (InterruptedException x) { /* ignore */ }
- mActive = STATE_NORMAL;
- }
-
- switch (state) {
- case SEND: {
- if (pipe.size() == maxPipe) {
- state = READ;
- break;
- }
- /* get a request */
- if (firstRequest == null) {
- req = mRequestFeeder.getRequest(mHost);
- } else {
- req = firstRequest;
- firstRequest = null;
- }
- if (req == null) {
- state = DRAIN;
- break;
- }
- req.setConnection(this);
-
- /* Don't work on cancelled requests. */
- if (req.mCancelled) {
- if (HttpLog.LOGV) HttpLog.v(
- "processRequests(): skipping cancelled request "
- + req);
- req.complete();
- break;
- }
-
- if (mHttpClientConnection == null ||
- !mHttpClientConnection.isOpen()) {
- /* If this call fails, the address is bad or
- the net is down. Punt for now.
-
- FIXME: blow out entire queue here on
- connection failure if net up? */
-
- if (!openHttpConnection(req)) {
- state = DONE;
- break;
- }
- }
-
- /* we have a connection, let the event handler
- * know of any associated certificate,
- * potentially none.
- */
- req.mEventHandler.certificate(mCertificate);
-
- try {
- /* FIXME: don't increment failure count if old
- connection? There should not be a penalty for
- attempting to reuse an old connection */
- req.sendRequest(mHttpClientConnection);
- } catch (HttpException e) {
- exception = e;
- error = EventHandler.ERROR;
- } catch (IOException e) {
- exception = e;
- error = EventHandler.ERROR_IO;
- } catch (IllegalStateException e) {
- exception = e;
- error = EventHandler.ERROR_IO;
- }
- if (exception != null) {
- if (httpFailure(req, error, exception) &&
- !req.mCancelled) {
- /* retry request if not permanent failure
- or cancelled */
- pipe.addLast(req);
- }
- exception = null;
- state = clearPipe(pipe) ? DONE : SEND;
- minPipe = maxPipe = 1;
- break;
- }
-
- pipe.addLast(req);
- if (!mCanPersist) state = READ;
- break;
-
- }
- case DRAIN:
- case READ: {
- empty = !mRequestFeeder.haveRequest(mHost);
- int pipeSize = pipe.size();
- if (state != DRAIN && pipeSize < minPipe &&
- !empty && mCanPersist) {
- state = SEND;
- break;
- } else if (pipeSize == 0) {
- /* Done if no other work to do */
- state = empty ? DONE : SEND;
- break;
- }
-
- req = (Request)pipe.removeFirst();
- if (HttpLog.LOGV) HttpLog.v(
- "processRequests() reading " + req);
-
- try {
- req.readResponse(mHttpClientConnection);
- } catch (ParseException e) {
- exception = e;
- error = EventHandler.ERROR_IO;
- } catch (IOException e) {
- exception = e;
- error = EventHandler.ERROR_IO;
- } catch (IllegalStateException e) {
- exception = e;
- error = EventHandler.ERROR_IO;
- }
- if (exception != null) {
- if (httpFailure(req, error, exception) &&
- !req.mCancelled) {
- /* retry request if not permanent failure
- or cancelled */
- req.reset();
- pipe.addFirst(req);
- }
- exception = null;
- mCanPersist = false;
- }
- if (!mCanPersist) {
- if (HttpLog.LOGV) HttpLog.v(
- "processRequests(): no persist, closing " +
- mHost);
-
- closeConnection();
-
- mHttpContext.removeAttribute(HTTP_CONNECTION);
- clearPipe(pipe);
- minPipe = maxPipe = 1;
- state = SEND;
- }
- break;
- }
- }
- }
- }
-
- /**
- * After a send/receive failure, any pipelined requests must be
- * cleared back to the mRequest queue
- * @return true if mRequests is empty after pipe cleared
- */
- private boolean clearPipe(LinkedList<Request> pipe) {
- boolean empty = true;
- if (HttpLog.LOGV) HttpLog.v(
- "Connection.clearPipe(): clearing pipe " + pipe.size());
- synchronized (mRequestFeeder) {
- Request tReq;
- while (!pipe.isEmpty()) {
- tReq = (Request)pipe.removeLast();
- if (HttpLog.LOGV) HttpLog.v(
- "clearPipe() adding back " + mHost + " " + tReq);
- mRequestFeeder.requeueRequest(tReq);
- empty = false;
- }
- if (empty) empty = !mRequestFeeder.haveRequest(mHost);
- }
- return empty;
- }
-
- /**
- * @return true on success
- */
- private boolean openHttpConnection(Request req) {
-
- long now = SystemClock.uptimeMillis();
- int error = EventHandler.OK;
- Exception exception = null;
-
- try {
- // reset the certificate to null before opening a connection
- mCertificate = null;
- mHttpClientConnection = openConnection(req);
- if (mHttpClientConnection != null) {
- mHttpClientConnection.setSocketTimeout(SOCKET_TIMEOUT);
- mHttpContext.setAttribute(HTTP_CONNECTION,
- mHttpClientConnection);
- } else {
- // we tried to do SSL tunneling, failed,
- // and need to drop the request;
- // we have already informed the handler
- req.mFailCount = RETRY_REQUEST_LIMIT;
- return false;
- }
- } catch (UnknownHostException e) {
- if (HttpLog.LOGV) HttpLog.v("Failed to open connection");
- error = EventHandler.ERROR_LOOKUP;
- exception = e;
- } catch (IllegalArgumentException e) {
- if (HttpLog.LOGV) HttpLog.v("Illegal argument exception");
- error = EventHandler.ERROR_CONNECT;
- req.mFailCount = RETRY_REQUEST_LIMIT;
- exception = e;
- } catch (SSLConnectionClosedByUserException e) {
- // hack: if we have an SSL connection failure,
- // we don't want to reconnect
- req.mFailCount = RETRY_REQUEST_LIMIT;
- // no error message
- return false;
- } catch (SSLHandshakeException e) {
- // hack: if we have an SSL connection failure,
- // we don't want to reconnect
- req.mFailCount = RETRY_REQUEST_LIMIT;
- if (HttpLog.LOGV) HttpLog.v(
- "SSL exception performing handshake");
- error = EventHandler.ERROR_FAILED_SSL_HANDSHAKE;
- exception = e;
- } catch (IOException e) {
- error = EventHandler.ERROR_CONNECT;
- exception = e;
- }
-
- if (HttpLog.LOGV) {
- long now2 = SystemClock.uptimeMillis();
- HttpLog.v("Connection.openHttpConnection() " +
- (now2 - now) + " " + mHost);
- }
-
- if (error == EventHandler.OK) {
- return true;
- } else {
- if (req.mFailCount < RETRY_REQUEST_LIMIT) {
- // requeue
- mRequestFeeder.requeueRequest(req);
- req.mFailCount++;
- } else {
- httpFailure(req, error, exception);
- }
- return error == EventHandler.OK;
- }
- }
-
- /**
- * Helper. Calls the mEventHandler's error() method only if
- * request failed permanently. Increments mFailcount on failure.
- *
- * Increments failcount only if the network is believed to be
- * connected
- *
- * @return true if request can be retried (less than
- * RETRY_REQUEST_LIMIT failures have occurred).
- */
- private boolean httpFailure(Request req, int errorId, Exception e) {
- boolean ret = true;
-
- // e.printStackTrace();
- if (HttpLog.LOGV) HttpLog.v(
- "httpFailure() ******* " + e + " count " + req.mFailCount +
- " " + mHost + " " + req.getUri());
-
- if (++req.mFailCount >= RETRY_REQUEST_LIMIT) {
- ret = false;
- String error;
- if (errorId < 0) {
- error = getEventHandlerErrorString(errorId);
- } else {
- Throwable cause = e.getCause();
- error = cause != null ? cause.toString() : e.getMessage();
- }
- req.mEventHandler.error(errorId, error);
- req.complete();
- }
-
- closeConnection();
- mHttpContext.removeAttribute(HTTP_CONNECTION);
-
- return ret;
- }
-
- private static String getEventHandlerErrorString(int errorId) {
- switch (errorId) {
- case EventHandler.OK:
- return "OK";
-
- case EventHandler.ERROR:
- return "ERROR";
-
- case EventHandler.ERROR_LOOKUP:
- return "ERROR_LOOKUP";
-
- case EventHandler.ERROR_UNSUPPORTED_AUTH_SCHEME:
- return "ERROR_UNSUPPORTED_AUTH_SCHEME";
-
- case EventHandler.ERROR_AUTH:
- return "ERROR_AUTH";
-
- case EventHandler.ERROR_PROXYAUTH:
- return "ERROR_PROXYAUTH";
-
- case EventHandler.ERROR_CONNECT:
- return "ERROR_CONNECT";
-
- case EventHandler.ERROR_IO:
- return "ERROR_IO";
-
- case EventHandler.ERROR_TIMEOUT:
- return "ERROR_TIMEOUT";
-
- case EventHandler.ERROR_REDIRECT_LOOP:
- return "ERROR_REDIRECT_LOOP";
-
- case EventHandler.ERROR_UNSUPPORTED_SCHEME:
- return "ERROR_UNSUPPORTED_SCHEME";
-
- case EventHandler.ERROR_FAILED_SSL_HANDSHAKE:
- return "ERROR_FAILED_SSL_HANDSHAKE";
-
- case EventHandler.ERROR_BAD_URL:
- return "ERROR_BAD_URL";
-
- case EventHandler.FILE_ERROR:
- return "FILE_ERROR";
-
- case EventHandler.FILE_NOT_FOUND_ERROR:
- return "FILE_NOT_FOUND_ERROR";
-
- case EventHandler.TOO_MANY_REQUESTS_ERROR:
- return "TOO_MANY_REQUESTS_ERROR";
-
- default:
- return "UNKNOWN_ERROR";
- }
- }
-
- HttpContext getHttpContext() {
- return mHttpContext;
- }
-
- /**
- * Use same logic as ConnectionReuseStrategy
- * @see ConnectionReuseStrategy
- */
- private boolean keepAlive(HttpEntity entity,
- ProtocolVersion ver, int connType, final HttpContext context) {
- org.apache.http.HttpConnection conn = (org.apache.http.HttpConnection)
- context.getAttribute(ExecutionContext.HTTP_CONNECTION);
-
- if (conn != null && !conn.isOpen())
- return false;
- // do NOT check for stale connection, that is an expensive operation
-
- if (entity != null) {
- if (entity.getContentLength() < 0) {
- if (!entity.isChunked() || ver.lessEquals(HttpVersion.HTTP_1_0)) {
- // if the content length is not known and is not chunk
- // encoded, the connection cannot be reused
- return false;
- }
- }
- }
- // Check for 'Connection' directive
- if (connType == Headers.CONN_CLOSE) {
- return false;
- } else if (connType == Headers.CONN_KEEP_ALIVE) {
- return true;
- }
- // Resorting to protocol version default close connection policy
- return !ver.lessEquals(HttpVersion.HTTP_1_0);
- }
-
- void setCanPersist(HttpEntity entity, ProtocolVersion ver, int connType) {
- mCanPersist = keepAlive(entity, ver, connType, mHttpContext);
- }
-
- void setCanPersist(boolean canPersist) {
- mCanPersist = canPersist;
- }
-
- boolean getCanPersist() {
- return mCanPersist;
- }
-
- /** typically http or https... set by subclass */
- abstract String getScheme();
- abstract void closeConnection();
- abstract AndroidHttpClientConnection openConnection(Request req) throws IOException;
-
- /**
- * Prints request queue to log, for debugging.
- * returns request count
- */
- public synchronized String toString() {
- return mHost.toString();
- }
-
- byte[] getBuf() {
- if (mBuf == null) mBuf = new byte[8192];
- return mBuf;
- }
-
-}
diff --git a/core/java/android/net/http/ConnectionThread.java b/core/java/android/net/http/ConnectionThread.java
deleted file mode 100644
index d825530..0000000
--- a/core/java/android/net/http/ConnectionThread.java
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.http;
-
-import android.content.Context;
-import android.os.SystemClock;
-
-import java.lang.Thread;
-
-/**
- * {@hide}
- */
-class ConnectionThread extends Thread {
-
- static final int WAIT_TIMEOUT = 5000;
- static final int WAIT_TICK = 1000;
-
- // Performance probe
- long mCurrentThreadTime;
- long mTotalThreadTime;
-
- private boolean mWaiting;
- private volatile boolean mRunning = true;
- private Context mContext;
- private RequestQueue.ConnectionManager mConnectionManager;
- private RequestFeeder mRequestFeeder;
-
- private int mId;
- Connection mConnection;
-
- ConnectionThread(Context context,
- int id,
- RequestQueue.ConnectionManager connectionManager,
- RequestFeeder requestFeeder) {
- super();
- mContext = context;
- setName("http" + id);
- mId = id;
- mConnectionManager = connectionManager;
- mRequestFeeder = requestFeeder;
- }
-
- void requestStop() {
- synchronized (mRequestFeeder) {
- mRunning = false;
- mRequestFeeder.notify();
- }
- }
-
- /**
- * Loop until app shutdown. Runs connections in priority
- * order.
- */
- public void run() {
- android.os.Process.setThreadPriority(
- android.os.Process.THREAD_PRIORITY_DEFAULT +
- android.os.Process.THREAD_PRIORITY_LESS_FAVORABLE);
-
- // these are used to get performance data. When it is not in the timing,
- // mCurrentThreadTime is 0. When it starts timing, mCurrentThreadTime is
- // first set to -1, it will be set to the current thread time when the
- // next request starts.
- mCurrentThreadTime = 0;
- mTotalThreadTime = 0;
-
- while (mRunning) {
- if (mCurrentThreadTime == -1) {
- mCurrentThreadTime = SystemClock.currentThreadTimeMillis();
- }
-
- Request request;
-
- /* Get a request to process */
- request = mRequestFeeder.getRequest();
-
- /* wait for work */
- if (request == null) {
- synchronized(mRequestFeeder) {
- if (HttpLog.LOGV) HttpLog.v("ConnectionThread: Waiting for work");
- mWaiting = true;
- try {
- mRequestFeeder.wait();
- } catch (InterruptedException e) {
- }
- mWaiting = false;
- if (mCurrentThreadTime != 0) {
- mCurrentThreadTime = SystemClock
- .currentThreadTimeMillis();
- }
- }
- } else {
- if (HttpLog.LOGV) HttpLog.v("ConnectionThread: new request " +
- request.mHost + " " + request );
-
- mConnection = mConnectionManager.getConnection(mContext,
- request.mHost);
- mConnection.processRequests(request);
- if (mConnection.getCanPersist()) {
- if (!mConnectionManager.recycleConnection(mConnection)) {
- mConnection.closeConnection();
- }
- } else {
- mConnection.closeConnection();
- }
- mConnection = null;
-
- if (mCurrentThreadTime > 0) {
- long start = mCurrentThreadTime;
- mCurrentThreadTime = SystemClock.currentThreadTimeMillis();
- mTotalThreadTime += mCurrentThreadTime - start;
- }
- }
-
- }
- }
-
- public synchronized String toString() {
- String con = mConnection == null ? "" : mConnection.toString();
- String active = mWaiting ? "w" : "a";
- return "cid " + mId + " " + active + " " + con;
- }
-
-}
diff --git a/core/java/android/net/http/DelegatingSSLSession.java b/core/java/android/net/http/DelegatingSSLSession.java
deleted file mode 100644
index 98fbe21..0000000
--- a/core/java/android/net/http/DelegatingSSLSession.java
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * Copyright 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.http;
-
-import java.security.Principal;
-import java.security.cert.Certificate;
-import java.security.cert.X509Certificate;
-
-import javax.net.ssl.SSLPeerUnverifiedException;
-import javax.net.ssl.SSLSession;
-import javax.net.ssl.SSLSessionContext;
-import javax.net.ssl.SSLSocket;
-import javax.net.ssl.X509TrustManager;
-
-/**
- * This is only used when a {@code certificate} is available but usage
- * requires a {@link SSLSession}.
- *
- * @hide
- */
-public class DelegatingSSLSession implements SSLSession {
- protected DelegatingSSLSession() {
- }
-
- public static class CertificateWrap extends DelegatingSSLSession {
- private final Certificate mCertificate;
-
- public CertificateWrap(Certificate certificate) {
- mCertificate = certificate;
- }
-
- @Override
- public Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException {
- return new Certificate[] { mCertificate };
- }
- }
-
-
- @Override
- public int getApplicationBufferSize() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public String getCipherSuite() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public long getCreationTime() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public byte[] getId() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public long getLastAccessedTime() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public Certificate[] getLocalCertificates() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public Principal getLocalPrincipal() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public int getPacketBufferSize() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public javax.security.cert.X509Certificate[] getPeerCertificateChain()
- throws SSLPeerUnverifiedException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public String getPeerHost() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public int getPeerPort() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public Principal getPeerPrincipal() throws SSLPeerUnverifiedException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public String getProtocol() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public SSLSessionContext getSessionContext() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public Object getValue(String name) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public String[] getValueNames() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void invalidate() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean isValid() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void putValue(String name, Object value) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void removeValue(String name) {
- throw new UnsupportedOperationException();
- }
-}
diff --git a/core/java/android/net/http/EventHandler.java b/core/java/android/net/http/EventHandler.java
deleted file mode 100644
index 3fd471d..0000000
--- a/core/java/android/net/http/EventHandler.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.http;
-
-
-/**
- * Callbacks in this interface are made as an HTTP request is
- * processed. The normal order of callbacks is status(), headers(),
- * then multiple data() then endData(). handleSslErrorRequest(), if
- * there is an SSL certificate error. error() can occur anywhere
- * in the transaction.
- *
- * {@hide}
- */
-
-public interface EventHandler {
-
- /**
- * Error codes used in the error() callback. Positive error codes
- * are reserved for codes sent by http servers. Negative error
- * codes are connection/parsing failures, etc.
- */
-
- /** Success */
- public static final int OK = 0;
- /** Generic error */
- public static final int ERROR = -1;
- /** Server or proxy hostname lookup failed */
- public static final int ERROR_LOOKUP = -2;
- /** Unsupported authentication scheme (ie, not basic or digest) */
- public static final int ERROR_UNSUPPORTED_AUTH_SCHEME = -3;
- /** User authentication failed on server */
- public static final int ERROR_AUTH = -4;
- /** User authentication failed on proxy */
- public static final int ERROR_PROXYAUTH = -5;
- /** Could not connect to server */
- public static final int ERROR_CONNECT = -6;
- /** Failed to write to or read from server */
- public static final int ERROR_IO = -7;
- /** Connection timed out */
- public static final int ERROR_TIMEOUT = -8;
- /** Too many redirects */
- public static final int ERROR_REDIRECT_LOOP = -9;
- /** Unsupported URI scheme (ie, not http, https, etc) */
- public static final int ERROR_UNSUPPORTED_SCHEME = -10;
- /** Failed to perform SSL handshake */
- public static final int ERROR_FAILED_SSL_HANDSHAKE = -11;
- /** Bad URL */
- public static final int ERROR_BAD_URL = -12;
- /** Generic file error for file:/// loads */
- public static final int FILE_ERROR = -13;
- /** File not found error for file:/// loads */
- public static final int FILE_NOT_FOUND_ERROR = -14;
- /** Too many requests queued */
- public static final int TOO_MANY_REQUESTS_ERROR = -15;
-
- /**
- * Called after status line has been sucessfully processed.
- * @param major_version HTTP version advertised by server. major
- * is the part before the "."
- * @param minor_version HTTP version advertised by server. minor
- * is the part after the "."
- * @param code HTTP Status code. See RFC 2616.
- * @param reason_phrase Textual explanation sent by server
- */
- public void status(int major_version,
- int minor_version,
- int code,
- String reason_phrase);
-
- /**
- * Called after all headers are successfully processed.
- */
- public void headers(Headers headers);
-
- /**
- * An array containing all or part of the http body as read from
- * the server.
- * @param data A byte array containing the content
- * @param len The length of valid content in data
- *
- * Note: chunked and compressed encodings are handled within
- * android.net.http. Decoded data is passed through this
- * interface.
- */
- public void data(byte[] data, int len);
-
- /**
- * Called when the document is completely read. No more data()
- * callbacks will be made after this call
- */
- public void endData();
-
- /**
- * SSL certificate callback called before resource request is
- * made, which will be null for insecure connection.
- */
- public void certificate(SslCertificate certificate);
-
- /**
- * There was trouble.
- * @param id One of the error codes defined below
- * @param description of error
- */
- public void error(int id, String description);
-
- /**
- * SSL certificate error callback. Handles SSL error(s) on the way
- * up to the user. The callback has to make sure that restartConnection() is called,
- * otherwise the connection will be suspended indefinitely.
- * @return True if the callback can handle the error, which means it will
- * call restartConnection() to unblock the thread later,
- * otherwise return false.
- */
- public boolean handleSslErrorRequest(SslError error);
-
-}
diff --git a/core/java/android/net/http/Headers.java b/core/java/android/net/http/Headers.java
deleted file mode 100644
index 0f8b105..0000000
--- a/core/java/android/net/http/Headers.java
+++ /dev/null
@@ -1,521 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.http;
-
-import android.util.Log;
-
-import java.util.ArrayList;
-
-import org.apache.http.HeaderElement;
-import org.apache.http.entity.ContentLengthStrategy;
-import org.apache.http.message.BasicHeaderValueParser;
-import org.apache.http.message.ParserCursor;
-import org.apache.http.protocol.HTTP;
-import org.apache.http.util.CharArrayBuffer;
-
-/**
- * Manages received headers
- *
- * {@hide}
- */
-public final class Headers {
- private static final String LOGTAG = "Http";
-
- // header parsing constant
- /**
- * indicate HTTP 1.0 connection close after the response
- */
- public final static int CONN_CLOSE = 1;
- /**
- * indicate HTTP 1.1 connection keep alive
- */
- public final static int CONN_KEEP_ALIVE = 2;
-
- // initial values.
- public final static int NO_CONN_TYPE = 0;
- public final static long NO_TRANSFER_ENCODING = 0;
- public final static long NO_CONTENT_LENGTH = -1;
-
- // header strings
- public final static String TRANSFER_ENCODING = "transfer-encoding";
- public final static String CONTENT_LEN = "content-length";
- public final static String CONTENT_TYPE = "content-type";
- public final static String CONTENT_ENCODING = "content-encoding";
- public final static String CONN_DIRECTIVE = "connection";
-
- public final static String LOCATION = "location";
- public final static String PROXY_CONNECTION = "proxy-connection";
-
- public final static String WWW_AUTHENTICATE = "www-authenticate";
- public final static String PROXY_AUTHENTICATE = "proxy-authenticate";
- public final static String CONTENT_DISPOSITION = "content-disposition";
- public final static String ACCEPT_RANGES = "accept-ranges";
- public final static String EXPIRES = "expires";
- public final static String CACHE_CONTROL = "cache-control";
- public final static String LAST_MODIFIED = "last-modified";
- public final static String ETAG = "etag";
- public final static String SET_COOKIE = "set-cookie";
- public final static String PRAGMA = "pragma";
- public final static String REFRESH = "refresh";
- public final static String X_PERMITTED_CROSS_DOMAIN_POLICIES = "x-permitted-cross-domain-policies";
-
- // following hash are generated by String.hashCode()
- private final static int HASH_TRANSFER_ENCODING = 1274458357;
- private final static int HASH_CONTENT_LEN = -1132779846;
- private final static int HASH_CONTENT_TYPE = 785670158;
- private final static int HASH_CONTENT_ENCODING = 2095084583;
- private final static int HASH_CONN_DIRECTIVE = -775651618;
- private final static int HASH_LOCATION = 1901043637;
- private final static int HASH_PROXY_CONNECTION = 285929373;
- private final static int HASH_WWW_AUTHENTICATE = -243037365;
- private final static int HASH_PROXY_AUTHENTICATE = -301767724;
- private final static int HASH_CONTENT_DISPOSITION = -1267267485;
- private final static int HASH_ACCEPT_RANGES = 1397189435;
- private final static int HASH_EXPIRES = -1309235404;
- private final static int HASH_CACHE_CONTROL = -208775662;
- private final static int HASH_LAST_MODIFIED = 150043680;
- private final static int HASH_ETAG = 3123477;
- private final static int HASH_SET_COOKIE = 1237214767;
- private final static int HASH_PRAGMA = -980228804;
- private final static int HASH_REFRESH = 1085444827;
- private final static int HASH_X_PERMITTED_CROSS_DOMAIN_POLICIES = -1345594014;
-
- // keep any headers that require direct access in a presized
- // string array
- private final static int IDX_TRANSFER_ENCODING = 0;
- private final static int IDX_CONTENT_LEN = 1;
- private final static int IDX_CONTENT_TYPE = 2;
- private final static int IDX_CONTENT_ENCODING = 3;
- private final static int IDX_CONN_DIRECTIVE = 4;
- private final static int IDX_LOCATION = 5;
- private final static int IDX_PROXY_CONNECTION = 6;
- private final static int IDX_WWW_AUTHENTICATE = 7;
- private final static int IDX_PROXY_AUTHENTICATE = 8;
- private final static int IDX_CONTENT_DISPOSITION = 9;
- private final static int IDX_ACCEPT_RANGES = 10;
- private final static int IDX_EXPIRES = 11;
- private final static int IDX_CACHE_CONTROL = 12;
- private final static int IDX_LAST_MODIFIED = 13;
- private final static int IDX_ETAG = 14;
- private final static int IDX_SET_COOKIE = 15;
- private final static int IDX_PRAGMA = 16;
- private final static int IDX_REFRESH = 17;
- private final static int IDX_X_PERMITTED_CROSS_DOMAIN_POLICIES = 18;
-
- private final static int HEADER_COUNT = 19;
-
- /* parsed values */
- private long transferEncoding;
- private long contentLength; // Content length of the incoming data
- private int connectionType;
- private ArrayList<String> cookies = new ArrayList<String>(2);
-
- private String[] mHeaders = new String[HEADER_COUNT];
- private final static String[] sHeaderNames = {
- TRANSFER_ENCODING,
- CONTENT_LEN,
- CONTENT_TYPE,
- CONTENT_ENCODING,
- CONN_DIRECTIVE,
- LOCATION,
- PROXY_CONNECTION,
- WWW_AUTHENTICATE,
- PROXY_AUTHENTICATE,
- CONTENT_DISPOSITION,
- ACCEPT_RANGES,
- EXPIRES,
- CACHE_CONTROL,
- LAST_MODIFIED,
- ETAG,
- SET_COOKIE,
- PRAGMA,
- REFRESH,
- X_PERMITTED_CROSS_DOMAIN_POLICIES
- };
-
- // Catch-all for headers not explicitly handled
- private ArrayList<String> mExtraHeaderNames = new ArrayList<String>(4);
- private ArrayList<String> mExtraHeaderValues = new ArrayList<String>(4);
-
- public Headers() {
- transferEncoding = NO_TRANSFER_ENCODING;
- contentLength = NO_CONTENT_LENGTH;
- connectionType = NO_CONN_TYPE;
- }
-
- public void parseHeader(CharArrayBuffer buffer) {
- int pos = setLowercaseIndexOf(buffer, ':');
- if (pos == -1) {
- return;
- }
- String name = buffer.substringTrimmed(0, pos);
- if (name.length() == 0) {
- return;
- }
- pos++;
-
- String val = buffer.substringTrimmed(pos, buffer.length());
- if (HttpLog.LOGV) {
- HttpLog.v("hdr " + buffer.length() + " " + buffer);
- }
-
- switch (name.hashCode()) {
- case HASH_TRANSFER_ENCODING:
- if (name.equals(TRANSFER_ENCODING)) {
- mHeaders[IDX_TRANSFER_ENCODING] = val;
- HeaderElement[] encodings = BasicHeaderValueParser.DEFAULT
- .parseElements(buffer, new ParserCursor(pos,
- buffer.length()));
- // The chunked encoding must be the last one applied RFC2616,
- // 14.41
- int len = encodings.length;
- if (HTTP.IDENTITY_CODING.equalsIgnoreCase(val)) {
- transferEncoding = ContentLengthStrategy.IDENTITY;
- } else if ((len > 0)
- && (HTTP.CHUNK_CODING
- .equalsIgnoreCase(encodings[len - 1].getName()))) {
- transferEncoding = ContentLengthStrategy.CHUNKED;
- } else {
- transferEncoding = ContentLengthStrategy.IDENTITY;
- }
- }
- break;
- case HASH_CONTENT_LEN:
- if (name.equals(CONTENT_LEN)) {
- mHeaders[IDX_CONTENT_LEN] = val;
- try {
- contentLength = Long.parseLong(val);
- } catch (NumberFormatException e) {
- if (false) {
- Log.v(LOGTAG, "Headers.headers(): error parsing"
- + " content length: " + buffer.toString());
- }
- }
- }
- break;
- case HASH_CONTENT_TYPE:
- if (name.equals(CONTENT_TYPE)) {
- mHeaders[IDX_CONTENT_TYPE] = val;
- }
- break;
- case HASH_CONTENT_ENCODING:
- if (name.equals(CONTENT_ENCODING)) {
- mHeaders[IDX_CONTENT_ENCODING] = val;
- }
- break;
- case HASH_CONN_DIRECTIVE:
- if (name.equals(CONN_DIRECTIVE)) {
- mHeaders[IDX_CONN_DIRECTIVE] = val;
- setConnectionType(buffer, pos);
- }
- break;
- case HASH_LOCATION:
- if (name.equals(LOCATION)) {
- mHeaders[IDX_LOCATION] = val;
- }
- break;
- case HASH_PROXY_CONNECTION:
- if (name.equals(PROXY_CONNECTION)) {
- mHeaders[IDX_PROXY_CONNECTION] = val;
- setConnectionType(buffer, pos);
- }
- break;
- case HASH_WWW_AUTHENTICATE:
- if (name.equals(WWW_AUTHENTICATE)) {
- mHeaders[IDX_WWW_AUTHENTICATE] = val;
- }
- break;
- case HASH_PROXY_AUTHENTICATE:
- if (name.equals(PROXY_AUTHENTICATE)) {
- mHeaders[IDX_PROXY_AUTHENTICATE] = val;
- }
- break;
- case HASH_CONTENT_DISPOSITION:
- if (name.equals(CONTENT_DISPOSITION)) {
- mHeaders[IDX_CONTENT_DISPOSITION] = val;
- }
- break;
- case HASH_ACCEPT_RANGES:
- if (name.equals(ACCEPT_RANGES)) {
- mHeaders[IDX_ACCEPT_RANGES] = val;
- }
- break;
- case HASH_EXPIRES:
- if (name.equals(EXPIRES)) {
- mHeaders[IDX_EXPIRES] = val;
- }
- break;
- case HASH_CACHE_CONTROL:
- if (name.equals(CACHE_CONTROL)) {
- // In case where we receive more than one header, create a ',' separated list.
- // This should be ok, according to RFC 2616 chapter 4.2
- if (mHeaders[IDX_CACHE_CONTROL] != null &&
- mHeaders[IDX_CACHE_CONTROL].length() > 0) {
- mHeaders[IDX_CACHE_CONTROL] += (',' + val);
- } else {
- mHeaders[IDX_CACHE_CONTROL] = val;
- }
- }
- break;
- case HASH_LAST_MODIFIED:
- if (name.equals(LAST_MODIFIED)) {
- mHeaders[IDX_LAST_MODIFIED] = val;
- }
- break;
- case HASH_ETAG:
- if (name.equals(ETAG)) {
- mHeaders[IDX_ETAG] = val;
- }
- break;
- case HASH_SET_COOKIE:
- if (name.equals(SET_COOKIE)) {
- mHeaders[IDX_SET_COOKIE] = val;
- cookies.add(val);
- }
- break;
- case HASH_PRAGMA:
- if (name.equals(PRAGMA)) {
- mHeaders[IDX_PRAGMA] = val;
- }
- break;
- case HASH_REFRESH:
- if (name.equals(REFRESH)) {
- mHeaders[IDX_REFRESH] = val;
- }
- break;
- case HASH_X_PERMITTED_CROSS_DOMAIN_POLICIES:
- if (name.equals(X_PERMITTED_CROSS_DOMAIN_POLICIES)) {
- mHeaders[IDX_X_PERMITTED_CROSS_DOMAIN_POLICIES] = val;
- }
- break;
- default:
- mExtraHeaderNames.add(name);
- mExtraHeaderValues.add(val);
- }
- }
-
- public long getTransferEncoding() {
- return transferEncoding;
- }
-
- public long getContentLength() {
- return contentLength;
- }
-
- public int getConnectionType() {
- return connectionType;
- }
-
- public String getContentType() {
- return mHeaders[IDX_CONTENT_TYPE];
- }
-
- public String getContentEncoding() {
- return mHeaders[IDX_CONTENT_ENCODING];
- }
-
- public String getLocation() {
- return mHeaders[IDX_LOCATION];
- }
-
- public String getWwwAuthenticate() {
- return mHeaders[IDX_WWW_AUTHENTICATE];
- }
-
- public String getProxyAuthenticate() {
- return mHeaders[IDX_PROXY_AUTHENTICATE];
- }
-
- public String getContentDisposition() {
- return mHeaders[IDX_CONTENT_DISPOSITION];
- }
-
- public String getAcceptRanges() {
- return mHeaders[IDX_ACCEPT_RANGES];
- }
-
- public String getExpires() {
- return mHeaders[IDX_EXPIRES];
- }
-
- public String getCacheControl() {
- return mHeaders[IDX_CACHE_CONTROL];
- }
-
- public String getLastModified() {
- return mHeaders[IDX_LAST_MODIFIED];
- }
-
- public String getEtag() {
- return mHeaders[IDX_ETAG];
- }
-
- public ArrayList<String> getSetCookie() {
- return this.cookies;
- }
-
- public String getPragma() {
- return mHeaders[IDX_PRAGMA];
- }
-
- public String getRefresh() {
- return mHeaders[IDX_REFRESH];
- }
-
- public String getXPermittedCrossDomainPolicies() {
- return mHeaders[IDX_X_PERMITTED_CROSS_DOMAIN_POLICIES];
- }
-
- public void setContentLength(long value) {
- this.contentLength = value;
- }
-
- public void setContentType(String value) {
- mHeaders[IDX_CONTENT_TYPE] = value;
- }
-
- public void setContentEncoding(String value) {
- mHeaders[IDX_CONTENT_ENCODING] = value;
- }
-
- public void setLocation(String value) {
- mHeaders[IDX_LOCATION] = value;
- }
-
- public void setWwwAuthenticate(String value) {
- mHeaders[IDX_WWW_AUTHENTICATE] = value;
- }
-
- public void setProxyAuthenticate(String value) {
- mHeaders[IDX_PROXY_AUTHENTICATE] = value;
- }
-
- public void setContentDisposition(String value) {
- mHeaders[IDX_CONTENT_DISPOSITION] = value;
- }
-
- public void setAcceptRanges(String value) {
- mHeaders[IDX_ACCEPT_RANGES] = value;
- }
-
- public void setExpires(String value) {
- mHeaders[IDX_EXPIRES] = value;
- }
-
- public void setCacheControl(String value) {
- mHeaders[IDX_CACHE_CONTROL] = value;
- }
-
- public void setLastModified(String value) {
- mHeaders[IDX_LAST_MODIFIED] = value;
- }
-
- public void setEtag(String value) {
- mHeaders[IDX_ETAG] = value;
- }
-
- public void setXPermittedCrossDomainPolicies(String value) {
- mHeaders[IDX_X_PERMITTED_CROSS_DOMAIN_POLICIES] = value;
- }
-
- public interface HeaderCallback {
- public void header(String name, String value);
- }
-
- /**
- * Reports all non-null headers to the callback
- */
- public void getHeaders(HeaderCallback hcb) {
- for (int i = 0; i < HEADER_COUNT; i++) {
- String h = mHeaders[i];
- if (h != null) {
- hcb.header(sHeaderNames[i], h);
- }
- }
- int extraLen = mExtraHeaderNames.size();
- for (int i = 0; i < extraLen; i++) {
- if (false) {
- HttpLog.v("Headers.getHeaders() extra: " + i + " " +
- mExtraHeaderNames.get(i) + " " + mExtraHeaderValues.get(i));
- }
- hcb.header(mExtraHeaderNames.get(i),
- mExtraHeaderValues.get(i));
- }
-
- }
-
- private void setConnectionType(CharArrayBuffer buffer, int pos) {
- if (containsIgnoreCaseTrimmed(buffer, pos, HTTP.CONN_CLOSE)) {
- connectionType = CONN_CLOSE;
- } else if (containsIgnoreCaseTrimmed(
- buffer, pos, HTTP.CONN_KEEP_ALIVE)) {
- connectionType = CONN_KEEP_ALIVE;
- }
- }
-
-
- /**
- * Returns true if the buffer contains the given string. Ignores leading
- * whitespace and case.
- *
- * @param buffer to search
- * @param beginIndex index at which we should start
- * @param str to search for
- */
- static boolean containsIgnoreCaseTrimmed(CharArrayBuffer buffer,
- int beginIndex, final String str) {
- int len = buffer.length();
- char[] chars = buffer.buffer();
- while (beginIndex < len && HTTP.isWhitespace(chars[beginIndex])) {
- beginIndex++;
- }
- int size = str.length();
- boolean ok = len >= (beginIndex + size);
- for (int j=0; ok && (j < size); j++) {
- char a = chars[beginIndex + j];
- char b = str.charAt(j);
- if (a != b) {
- a = Character.toLowerCase(a);
- b = Character.toLowerCase(b);
- ok = a == b;
- }
- }
-
- return true;
- }
-
- /**
- * Returns index of first occurence ch. Lower cases characters leading up
- * to first occurrence of ch.
- */
- static int setLowercaseIndexOf(CharArrayBuffer buffer, final int ch) {
-
- int beginIndex = 0;
- int endIndex = buffer.length();
- char[] chars = buffer.buffer();
-
- for (int i = beginIndex; i < endIndex; i++) {
- char current = chars[i];
- if (current == ch) {
- return i;
- } else {
- chars[i] = Character.toLowerCase(current);
- }
- }
- return -1;
- }
-}
diff --git a/core/java/android/net/http/HttpAuthHeader.java b/core/java/android/net/http/HttpAuthHeader.java
deleted file mode 100644
index 3abac23..0000000
--- a/core/java/android/net/http/HttpAuthHeader.java
+++ /dev/null
@@ -1,424 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.http;
-
-import java.util.Locale;
-
-/**
- * HttpAuthHeader: a class to store HTTP authentication-header parameters.
- * For more information, see: RFC 2617: HTTP Authentication.
- *
- * {@hide}
- */
-public class HttpAuthHeader {
- /**
- * Possible HTTP-authentication header tokens to search for:
- */
- public final static String BASIC_TOKEN = "Basic";
- public final static String DIGEST_TOKEN = "Digest";
-
- private final static String REALM_TOKEN = "realm";
- private final static String NONCE_TOKEN = "nonce";
- private final static String STALE_TOKEN = "stale";
- private final static String OPAQUE_TOKEN = "opaque";
- private final static String QOP_TOKEN = "qop";
- private final static String ALGORITHM_TOKEN = "algorithm";
-
- /**
- * An authentication scheme. We currently support two different schemes:
- * HttpAuthHeader.BASIC - basic, and
- * HttpAuthHeader.DIGEST - digest (algorithm=MD5, QOP="auth").
- */
- private int mScheme;
-
- public static final int UNKNOWN = 0;
- public static final int BASIC = 1;
- public static final int DIGEST = 2;
-
- /**
- * A flag, indicating that the previous request from the client was
- * rejected because the nonce value was stale. If stale is TRUE
- * (case-insensitive), the client may wish to simply retry the request
- * with a new encrypted response, without reprompting the user for a
- * new username and password.
- */
- private boolean mStale;
-
- /**
- * A string to be displayed to users so they know which username and
- * password to use.
- */
- private String mRealm;
-
- /**
- * A server-specified data string which should be uniquely generated
- * each time a 401 response is made.
- */
- private String mNonce;
-
- /**
- * A string of data, specified by the server, which should be returned
- * by the client unchanged in the Authorization header of subsequent
- * requests with URIs in the same protection space.
- */
- private String mOpaque;
-
- /**
- * This directive is optional, but is made so only for backward
- * compatibility with RFC 2069 [6]; it SHOULD be used by all
- * implementations compliant with this version of the Digest scheme.
- * If present, it is a quoted string of one or more tokens indicating
- * the "quality of protection" values supported by the server. The
- * value "auth" indicates authentication; the value "auth-int"
- * indicates authentication with integrity protection.
- */
- private String mQop;
-
- /**
- * A string indicating a pair of algorithms used to produce the digest
- * and a checksum. If this is not present it is assumed to be "MD5".
- */
- private String mAlgorithm;
-
- /**
- * Is this authentication request a proxy authentication request?
- */
- private boolean mIsProxy;
-
- /**
- * Username string we get from the user.
- */
- private String mUsername;
-
- /**
- * Password string we get from the user.
- */
- private String mPassword;
-
- /**
- * Creates a new HTTP-authentication header object from the
- * input header string.
- * The header string is assumed to contain parameters of at
- * most one authentication-scheme (ensured by the caller).
- */
- public HttpAuthHeader(String header) {
- if (header != null) {
- parseHeader(header);
- }
- }
-
- /**
- * @return True iff this is a proxy authentication header.
- */
- public boolean isProxy() {
- return mIsProxy;
- }
-
- /**
- * Marks this header as a proxy authentication header.
- */
- public void setProxy() {
- mIsProxy = true;
- }
-
- /**
- * @return The username string.
- */
- public String getUsername() {
- return mUsername;
- }
-
- /**
- * Sets the username string.
- */
- public void setUsername(String username) {
- mUsername = username;
- }
-
- /**
- * @return The password string.
- */
- public String getPassword() {
- return mPassword;
- }
-
- /**
- * Sets the password string.
- */
- public void setPassword(String password) {
- mPassword = password;
- }
-
- /**
- * @return True iff this is the BASIC-authentication request.
- */
- public boolean isBasic () {
- return mScheme == BASIC;
- }
-
- /**
- * @return True iff this is the DIGEST-authentication request.
- */
- public boolean isDigest() {
- return mScheme == DIGEST;
- }
-
- /**
- * @return The authentication scheme requested. We currently
- * support two schemes:
- * HttpAuthHeader.BASIC - basic, and
- * HttpAuthHeader.DIGEST - digest (algorithm=MD5, QOP="auth").
- */
- public int getScheme() {
- return mScheme;
- }
-
- /**
- * @return True if indicating that the previous request from
- * the client was rejected because the nonce value was stale.
- */
- public boolean getStale() {
- return mStale;
- }
-
- /**
- * @return The realm value or null if there is none.
- */
- public String getRealm() {
- return mRealm;
- }
-
- /**
- * @return The nonce value or null if there is none.
- */
- public String getNonce() {
- return mNonce;
- }
-
- /**
- * @return The opaque value or null if there is none.
- */
- public String getOpaque() {
- return mOpaque;
- }
-
- /**
- * @return The QOP ("quality-of_protection") value or null if
- * there is none. The QOP value is always lower-case.
- */
- public String getQop() {
- return mQop;
- }
-
- /**
- * @return The name of the algorithm used or null if there is
- * none. By default, MD5 is used.
- */
- public String getAlgorithm() {
- return mAlgorithm;
- }
-
- /**
- * @return True iff the authentication scheme requested by the
- * server is supported; currently supported schemes:
- * BASIC,
- * DIGEST (only algorithm="md5", no qop or qop="auth).
- */
- public boolean isSupportedScheme() {
- // it is a good idea to enforce non-null realms!
- if (mRealm != null) {
- if (mScheme == BASIC) {
- return true;
- } else {
- if (mScheme == DIGEST) {
- return
- mAlgorithm.equals("md5") &&
- (mQop == null || mQop.equals("auth"));
- }
- }
- }
-
- return false;
- }
-
- /**
- * Parses the header scheme name and then scheme parameters if
- * the scheme is supported.
- */
- private void parseHeader(String header) {
- if (HttpLog.LOGV) {
- HttpLog.v("HttpAuthHeader.parseHeader(): header: " + header);
- }
-
- if (header != null) {
- String parameters = parseScheme(header);
- if (parameters != null) {
- // if we have a supported scheme
- if (mScheme != UNKNOWN) {
- parseParameters(parameters);
- }
- }
- }
- }
-
- /**
- * Parses the authentication scheme name. If we have a Digest
- * scheme, sets the algorithm value to the default of MD5.
- * @return The authentication scheme parameters string to be
- * parsed later (if the scheme is supported) or null if failed
- * to parse the scheme (the header value is null?).
- */
- private String parseScheme(String header) {
- if (header != null) {
- int i = header.indexOf(' ');
- if (i >= 0) {
- String scheme = header.substring(0, i).trim();
- if (scheme.equalsIgnoreCase(DIGEST_TOKEN)) {
- mScheme = DIGEST;
-
- // md5 is the default algorithm!!!
- mAlgorithm = "md5";
- } else {
- if (scheme.equalsIgnoreCase(BASIC_TOKEN)) {
- mScheme = BASIC;
- }
- }
-
- return header.substring(i + 1);
- }
- }
-
- return null;
- }
-
- /**
- * Parses a comma-separated list of authentification scheme
- * parameters.
- */
- private void parseParameters(String parameters) {
- if (HttpLog.LOGV) {
- HttpLog.v("HttpAuthHeader.parseParameters():" +
- " parameters: " + parameters);
- }
-
- if (parameters != null) {
- int i;
- do {
- i = parameters.indexOf(',');
- if (i < 0) {
- // have only one parameter
- parseParameter(parameters);
- } else {
- parseParameter(parameters.substring(0, i));
- parameters = parameters.substring(i + 1);
- }
- } while (i >= 0);
- }
- }
-
- /**
- * Parses a single authentication scheme parameter. The parameter
- * string is expected to follow the format: PARAMETER=VALUE.
- */
- private void parseParameter(String parameter) {
- if (parameter != null) {
- // here, we are looking for the 1st occurence of '=' only!!!
- int i = parameter.indexOf('=');
- if (i >= 0) {
- String token = parameter.substring(0, i).trim();
- String value =
- trimDoubleQuotesIfAny(parameter.substring(i + 1).trim());
-
- if (HttpLog.LOGV) {
- HttpLog.v("HttpAuthHeader.parseParameter():" +
- " token: " + token +
- " value: " + value);
- }
-
- if (token.equalsIgnoreCase(REALM_TOKEN)) {
- mRealm = value;
- } else {
- if (mScheme == DIGEST) {
- parseParameter(token, value);
- }
- }
- }
- }
- }
-
- /**
- * If the token is a known parameter name, parses and initializes
- * the token value.
- */
- private void parseParameter(String token, String value) {
- if (token != null && value != null) {
- if (token.equalsIgnoreCase(NONCE_TOKEN)) {
- mNonce = value;
- return;
- }
-
- if (token.equalsIgnoreCase(STALE_TOKEN)) {
- parseStale(value);
- return;
- }
-
- if (token.equalsIgnoreCase(OPAQUE_TOKEN)) {
- mOpaque = value;
- return;
- }
-
- if (token.equalsIgnoreCase(QOP_TOKEN)) {
- mQop = value.toLowerCase(Locale.ROOT);
- return;
- }
-
- if (token.equalsIgnoreCase(ALGORITHM_TOKEN)) {
- mAlgorithm = value.toLowerCase(Locale.ROOT);
- return;
- }
- }
- }
-
- /**
- * Parses and initializes the 'stale' paramer value. Any value
- * different from case-insensitive "true" is considered "false".
- */
- private void parseStale(String value) {
- if (value != null) {
- if (value.equalsIgnoreCase("true")) {
- mStale = true;
- }
- }
- }
-
- /**
- * Trims double-quotes around a parameter value if there are any.
- * @return The string value without the outermost pair of double-
- * quotes or null if the original value is null.
- */
- static private String trimDoubleQuotesIfAny(String value) {
- if (value != null) {
- int len = value.length();
- if (len > 2 &&
- value.charAt(0) == '\"' && value.charAt(len - 1) == '\"') {
- return value.substring(1, len - 1);
- }
- }
-
- return value;
- }
-}
diff --git a/core/java/android/net/http/HttpConnection.java b/core/java/android/net/http/HttpConnection.java
deleted file mode 100644
index edf8fed3..0000000
--- a/core/java/android/net/http/HttpConnection.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.http;
-
-import android.content.Context;
-
-import java.net.Socket;
-import java.io.IOException;
-
-import org.apache.http.HttpHost;
-import org.apache.http.params.BasicHttpParams;
-import org.apache.http.params.HttpConnectionParams;
-
-/**
- * A requestConnection connecting to a normal (non secure) http server
- *
- * {@hide}
- */
-class HttpConnection extends Connection {
-
- HttpConnection(Context context, HttpHost host,
- RequestFeeder requestFeeder) {
- super(context, host, requestFeeder);
- }
-
- /**
- * Opens the connection to a http server
- *
- * @return the opened low level connection
- * @throws IOException if the connection fails for any reason.
- */
- @Override
- AndroidHttpClientConnection openConnection(Request req) throws IOException {
-
- // Update the certificate info (connection not secure - set to null)
- EventHandler eventHandler = req.getEventHandler();
- mCertificate = null;
- eventHandler.certificate(mCertificate);
-
- AndroidHttpClientConnection conn = new AndroidHttpClientConnection();
- BasicHttpParams params = new BasicHttpParams();
- Socket sock = new Socket(mHost.getHostName(), mHost.getPort());
- params.setIntParameter(HttpConnectionParams.SOCKET_BUFFER_SIZE, 8192);
- conn.bind(sock, params);
- return conn;
- }
-
- /**
- * Closes the low level connection.
- *
- * If an exception is thrown then it is assumed that the
- * connection will have been closed (to the extent possible)
- * anyway and the caller does not need to take any further action.
- *
- */
- void closeConnection() {
- try {
- if (mHttpClientConnection != null && mHttpClientConnection.isOpen()) {
- mHttpClientConnection.close();
- }
- } catch (IOException e) {
- if (HttpLog.LOGV) HttpLog.v(
- "closeConnection(): failed closing connection " +
- mHost);
- e.printStackTrace();
- }
- }
-
- /**
- * Restart a secure connection suspended waiting for user interaction.
- */
- void restartConnection(boolean abort) {
- // not required for plain http connections
- }
-
- String getScheme() {
- return "http";
- }
-}
diff --git a/core/java/android/net/http/HttpLog.java b/core/java/android/net/http/HttpLog.java
deleted file mode 100644
index 0934664..0000000
--- a/core/java/android/net/http/HttpLog.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**
- * package-level logging flag
- */
-
-package android.net.http;
-
-import android.os.SystemClock;
-
-import android.util.Log;
-
-/**
- * {@hide}
- */
-class HttpLog {
- private final static String LOGTAG = "http";
-
- private static final boolean DEBUG = false;
- static final boolean LOGV = false;
-
- static void v(String logMe) {
- Log.v(LOGTAG, SystemClock.uptimeMillis() + " " + Thread.currentThread().getName() + " " + logMe);
- }
-
- static void e(String logMe) {
- Log.e(LOGTAG, logMe);
- }
-}
diff --git a/core/java/android/net/http/HttpResponseCache.java b/core/java/android/net/http/HttpResponseCache.java
index c6c22e7..188287f 100644
--- a/core/java/android/net/http/HttpResponseCache.java
+++ b/core/java/android/net/http/HttpResponseCache.java
@@ -35,8 +35,8 @@ import java.util.Map;
* Caches HTTP and HTTPS responses to the filesystem so they may be reused,
* saving time and bandwidth. This class supports {@link
* java.net.HttpURLConnection} and {@link javax.net.ssl.HttpsURLConnection};
- * there is no platform-provided cache for {@link
- * org.apache.http.impl.client.DefaultHttpClient} or {@link AndroidHttpClient}.
+ * there is no platform-provided cache for {@code DefaultHttpClient} or
+ * {@code AndroidHttpClient}.
*
* <h3>Installing an HTTP response cache</h3>
* Enable caching of all of your application's HTTP requests by installing the
diff --git a/core/java/android/net/http/HttpsConnection.java b/core/java/android/net/http/HttpsConnection.java
deleted file mode 100644
index a8674de..0000000
--- a/core/java/android/net/http/HttpsConnection.java
+++ /dev/null
@@ -1,433 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.http;
-
-import android.content.Context;
-import android.util.Log;
-import com.android.org.conscrypt.FileClientSessionCache;
-import com.android.org.conscrypt.OpenSSLContextImpl;
-import com.android.org.conscrypt.SSLClientSessionCache;
-import org.apache.http.Header;
-import org.apache.http.HttpException;
-import org.apache.http.HttpHost;
-import org.apache.http.HttpStatus;
-import org.apache.http.ParseException;
-import org.apache.http.ProtocolVersion;
-import org.apache.http.StatusLine;
-import org.apache.http.message.BasicHttpRequest;
-import org.apache.http.params.BasicHttpParams;
-import org.apache.http.params.HttpConnectionParams;
-import org.apache.http.params.HttpParams;
-
-import javax.net.ssl.SSLException;
-import javax.net.ssl.SSLSocket;
-import javax.net.ssl.SSLSocketFactory;
-import javax.net.ssl.TrustManager;
-import javax.net.ssl.X509TrustManager;
-import java.io.File;
-import java.io.IOException;
-import java.net.Socket;
-import java.security.KeyManagementException;
-import java.security.cert.X509Certificate;
-import java.util.Locale;
-
-/**
- * A Connection connecting to a secure http server or tunneling through
- * a http proxy server to a https server.
- *
- * @hide
- */
-public class HttpsConnection extends Connection {
-
- /**
- * SSL socket factory
- */
- private static SSLSocketFactory mSslSocketFactory = null;
-
- static {
- // This initialization happens in the zygote. It triggers some
- // lazy initialization that can will benefit later invocations of
- // initializeEngine().
- initializeEngine(null);
- }
-
- /**
- * @hide
- *
- * @param sessionDir directory to cache SSL sessions
- */
- public static void initializeEngine(File sessionDir) {
- try {
- SSLClientSessionCache cache = null;
- if (sessionDir != null) {
- Log.d("HttpsConnection", "Caching SSL sessions in "
- + sessionDir + ".");
- cache = FileClientSessionCache.usingDirectory(sessionDir);
- }
-
- OpenSSLContextImpl sslContext = OpenSSLContextImpl.getPreferred();
-
- // here, trust managers is a single trust-all manager
- TrustManager[] trustManagers = new TrustManager[] {
- new X509TrustManager() {
- public X509Certificate[] getAcceptedIssuers() {
- return null;
- }
-
- public void checkClientTrusted(
- X509Certificate[] certs, String authType) {
- }
-
- public void checkServerTrusted(
- X509Certificate[] certs, String authType) {
- }
- }
- };
-
- sslContext.engineInit(null, trustManagers, null);
- sslContext.engineGetClientSessionContext().setPersistentCache(cache);
-
- synchronized (HttpsConnection.class) {
- mSslSocketFactory = sslContext.engineGetSocketFactory();
- }
- } catch (KeyManagementException e) {
- throw new RuntimeException(e);
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
-
- private synchronized static SSLSocketFactory getSocketFactory() {
- return mSslSocketFactory;
- }
-
- /**
- * Object to wait on when suspending the SSL connection
- */
- private Object mSuspendLock = new Object();
-
- /**
- * True if the connection is suspended pending the result of asking the
- * user about an error.
- */
- private boolean mSuspended = false;
-
- /**
- * True if the connection attempt should be aborted due to an ssl
- * error.
- */
- private boolean mAborted = false;
-
- // Used when connecting through a proxy.
- private HttpHost mProxyHost;
-
- /**
- * Contructor for a https connection.
- */
- HttpsConnection(Context context, HttpHost host, HttpHost proxy,
- RequestFeeder requestFeeder) {
- super(context, host, requestFeeder);
- mProxyHost = proxy;
- }
-
- /**
- * Sets the server SSL certificate associated with this
- * connection.
- * @param certificate The SSL certificate
- */
- /* package */ void setCertificate(SslCertificate certificate) {
- mCertificate = certificate;
- }
-
- /**
- * Opens the connection to a http server or proxy.
- *
- * @return the opened low level connection
- * @throws IOException if the connection fails for any reason.
- */
- @Override
- AndroidHttpClientConnection openConnection(Request req) throws IOException {
- SSLSocket sslSock = null;
-
- if (mProxyHost != null) {
- // If we have a proxy set, we first send a CONNECT request
- // to the proxy; if the proxy returns 200 OK, we negotiate
- // a secure connection to the target server via the proxy.
- // If the request fails, we drop it, but provide the event
- // handler with the response status and headers. The event
- // handler is then responsible for cancelling the load or
- // issueing a new request.
- AndroidHttpClientConnection proxyConnection = null;
- Socket proxySock = null;
- try {
- proxySock = new Socket
- (mProxyHost.getHostName(), mProxyHost.getPort());
-
- proxySock.setSoTimeout(60 * 1000);
-
- proxyConnection = new AndroidHttpClientConnection();
- HttpParams params = new BasicHttpParams();
- HttpConnectionParams.setSocketBufferSize(params, 8192);
-
- proxyConnection.bind(proxySock, params);
- } catch(IOException e) {
- if (proxyConnection != null) {
- proxyConnection.close();
- }
-
- String errorMessage = e.getMessage();
- if (errorMessage == null) {
- errorMessage =
- "failed to establish a connection to the proxy";
- }
-
- throw new IOException(errorMessage);
- }
-
- StatusLine statusLine = null;
- int statusCode = 0;
- Headers headers = new Headers();
- try {
- BasicHttpRequest proxyReq = new BasicHttpRequest
- ("CONNECT", mHost.toHostString());
-
- // add all 'proxy' headers from the original request, we also need
- // to add 'host' header unless we want proxy to answer us with a
- // 400 Bad Request
- for (Header h : req.mHttpRequest.getAllHeaders()) {
- String headerName = h.getName().toLowerCase(Locale.ROOT);
- if (headerName.startsWith("proxy") || headerName.equals("keep-alive")
- || headerName.equals("host")) {
- proxyReq.addHeader(h);
- }
- }
-
- proxyConnection.sendRequestHeader(proxyReq);
- proxyConnection.flush();
-
- // it is possible to receive informational status
- // codes prior to receiving actual headers;
- // all those status codes are smaller than OK 200
- // a loop is a standard way of dealing with them
- do {
- statusLine = proxyConnection.parseResponseHeader(headers);
- statusCode = statusLine.getStatusCode();
- } while (statusCode < HttpStatus.SC_OK);
- } catch (ParseException e) {
- String errorMessage = e.getMessage();
- if (errorMessage == null) {
- errorMessage =
- "failed to send a CONNECT request";
- }
-
- throw new IOException(errorMessage);
- } catch (HttpException e) {
- String errorMessage = e.getMessage();
- if (errorMessage == null) {
- errorMessage =
- "failed to send a CONNECT request";
- }
-
- throw new IOException(errorMessage);
- } catch (IOException e) {
- String errorMessage = e.getMessage();
- if (errorMessage == null) {
- errorMessage =
- "failed to send a CONNECT request";
- }
-
- throw new IOException(errorMessage);
- }
-
- if (statusCode == HttpStatus.SC_OK) {
- try {
- sslSock = (SSLSocket) getSocketFactory().createSocket(
- proxySock, mHost.getHostName(), mHost.getPort(), true);
- } catch(IOException e) {
- if (sslSock != null) {
- sslSock.close();
- }
-
- String errorMessage = e.getMessage();
- if (errorMessage == null) {
- errorMessage =
- "failed to create an SSL socket";
- }
- throw new IOException(errorMessage);
- }
- } else {
- // if the code is not OK, inform the event handler
- ProtocolVersion version = statusLine.getProtocolVersion();
-
- req.mEventHandler.status(version.getMajor(),
- version.getMinor(),
- statusCode,
- statusLine.getReasonPhrase());
- req.mEventHandler.headers(headers);
- req.mEventHandler.endData();
-
- proxyConnection.close();
-
- // here, we return null to indicate that the original
- // request needs to be dropped
- return null;
- }
- } else {
- // if we do not have a proxy, we simply connect to the host
- try {
- sslSock = (SSLSocket) getSocketFactory().createSocket(
- mHost.getHostName(), mHost.getPort());
- sslSock.setSoTimeout(SOCKET_TIMEOUT);
- } catch(IOException e) {
- if (sslSock != null) {
- sslSock.close();
- }
-
- String errorMessage = e.getMessage();
- if (errorMessage == null) {
- errorMessage = "failed to create an SSL socket";
- }
-
- throw new IOException(errorMessage);
- }
- }
-
- // do handshake and validate server certificates
- SslError error = CertificateChainValidator.getInstance().
- doHandshakeAndValidateServerCertificates(this, sslSock, mHost.getHostName());
-
- // Inform the user if there is a problem
- if (error != null) {
- // handleSslErrorRequest may immediately unsuspend if it wants to
- // allow the certificate anyway.
- // So we mark the connection as suspended, call handleSslErrorRequest
- // then check if we're still suspended and only wait if we actually
- // need to.
- synchronized (mSuspendLock) {
- mSuspended = true;
- }
- // don't hold the lock while calling out to the event handler
- boolean canHandle = req.getEventHandler().handleSslErrorRequest(error);
- if(!canHandle) {
- throw new IOException("failed to handle "+ error);
- }
- synchronized (mSuspendLock) {
- if (mSuspended) {
- try {
- // Put a limit on how long we are waiting; if the timeout
- // expires (which should never happen unless you choose
- // to ignore the SSL error dialog for a very long time),
- // we wake up the thread and abort the request. This is
- // to prevent us from stalling the network if things go
- // very bad.
- mSuspendLock.wait(10 * 60 * 1000);
- if (mSuspended) {
- // mSuspended is true if we have not had a chance to
- // restart the connection yet (ie, the wait timeout
- // has expired)
- mSuspended = false;
- mAborted = true;
- if (HttpLog.LOGV) {
- HttpLog.v("HttpsConnection.openConnection():" +
- " SSL timeout expired and request was cancelled!!!");
- }
- }
- } catch (InterruptedException e) {
- // ignore
- }
- }
- if (mAborted) {
- // The user decided not to use this unverified connection
- // so close it immediately.
- sslSock.close();
- throw new SSLConnectionClosedByUserException("connection closed by the user");
- }
- }
- }
-
- // All went well, we have an open, verified connection.
- AndroidHttpClientConnection conn = new AndroidHttpClientConnection();
- BasicHttpParams params = new BasicHttpParams();
- params.setIntParameter(HttpConnectionParams.SOCKET_BUFFER_SIZE, 8192);
- conn.bind(sslSock, params);
-
- return conn;
- }
-
- /**
- * Closes the low level connection.
- *
- * If an exception is thrown then it is assumed that the connection will
- * have been closed (to the extent possible) anyway and the caller does not
- * need to take any further action.
- *
- */
- @Override
- void closeConnection() {
- // if the connection has been suspended due to an SSL error
- if (mSuspended) {
- // wake up the network thread
- restartConnection(false);
- }
-
- try {
- if (mHttpClientConnection != null && mHttpClientConnection.isOpen()) {
- mHttpClientConnection.close();
- }
- } catch (IOException e) {
- if (HttpLog.LOGV)
- HttpLog.v("HttpsConnection.closeConnection():" +
- " failed closing connection " + mHost);
- e.printStackTrace();
- }
- }
-
- /**
- * Restart a secure connection suspended waiting for user interaction.
- */
- void restartConnection(boolean proceed) {
- if (HttpLog.LOGV) {
- HttpLog.v("HttpsConnection.restartConnection():" +
- " proceed: " + proceed);
- }
-
- synchronized (mSuspendLock) {
- if (mSuspended) {
- mSuspended = false;
- mAborted = !proceed;
- mSuspendLock.notify();
- }
- }
- }
-
- @Override
- String getScheme() {
- return "https";
- }
-}
-
-/**
- * Simple exception we throw if the SSL connection is closed by the user.
- *
- * {@hide}
- */
-class SSLConnectionClosedByUserException extends SSLException {
-
- public SSLConnectionClosedByUserException(String reason) {
- super(reason);
- }
-}
diff --git a/core/java/android/net/http/IdleCache.java b/core/java/android/net/http/IdleCache.java
deleted file mode 100644
index fda6009..0000000
--- a/core/java/android/net/http/IdleCache.java
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**
- * Hangs onto idle live connections for a little while
- */
-
-package android.net.http;
-
-import org.apache.http.HttpHost;
-
-import android.os.SystemClock;
-
-/**
- * {@hide}
- */
-class IdleCache {
-
- class Entry {
- HttpHost mHost;
- Connection mConnection;
- long mTimeout;
- };
-
- private final static int IDLE_CACHE_MAX = 8;
-
- /* Allow five consecutive empty queue checks before shutdown */
- private final static int EMPTY_CHECK_MAX = 5;
-
- /* six second timeout for connections */
- private final static int TIMEOUT = 6 * 1000;
- private final static int CHECK_INTERVAL = 2 * 1000;
- private Entry[] mEntries = new Entry[IDLE_CACHE_MAX];
-
- private int mCount = 0;
-
- private IdleReaper mThread = null;
-
- /* stats */
- private int mCached = 0;
- private int mReused = 0;
-
- IdleCache() {
- for (int i = 0; i < IDLE_CACHE_MAX; i++) {
- mEntries[i] = new Entry();
- }
- }
-
- /**
- * Caches connection, if there is room.
- * @return true if connection cached
- */
- synchronized boolean cacheConnection(
- HttpHost host, Connection connection) {
-
- boolean ret = false;
-
- if (HttpLog.LOGV) {
- HttpLog.v("IdleCache size " + mCount + " host " + host);
- }
-
- if (mCount < IDLE_CACHE_MAX) {
- long time = SystemClock.uptimeMillis();
- for (int i = 0; i < IDLE_CACHE_MAX; i++) {
- Entry entry = mEntries[i];
- if (entry.mHost == null) {
- entry.mHost = host;
- entry.mConnection = connection;
- entry.mTimeout = time + TIMEOUT;
- mCount++;
- if (HttpLog.LOGV) mCached++;
- ret = true;
- if (mThread == null) {
- mThread = new IdleReaper();
- mThread.start();
- }
- break;
- }
- }
- }
- return ret;
- }
-
- synchronized Connection getConnection(HttpHost host) {
- Connection ret = null;
-
- if (mCount > 0) {
- for (int i = 0; i < IDLE_CACHE_MAX; i++) {
- Entry entry = mEntries[i];
- HttpHost eHost = entry.mHost;
- if (eHost != null && eHost.equals(host)) {
- ret = entry.mConnection;
- entry.mHost = null;
- entry.mConnection = null;
- mCount--;
- if (HttpLog.LOGV) mReused++;
- break;
- }
- }
- }
- return ret;
- }
-
- synchronized void clear() {
- for (int i = 0; mCount > 0 && i < IDLE_CACHE_MAX; i++) {
- Entry entry = mEntries[i];
- if (entry.mHost != null) {
- entry.mHost = null;
- entry.mConnection.closeConnection();
- entry.mConnection = null;
- mCount--;
- }
- }
- }
-
- private synchronized void clearIdle() {
- if (mCount > 0) {
- long time = SystemClock.uptimeMillis();
- for (int i = 0; i < IDLE_CACHE_MAX; i++) {
- Entry entry = mEntries[i];
- if (entry.mHost != null && time > entry.mTimeout) {
- entry.mHost = null;
- entry.mConnection.closeConnection();
- entry.mConnection = null;
- mCount--;
- }
- }
- }
- }
-
- private class IdleReaper extends Thread {
-
- public void run() {
- int check = 0;
-
- setName("IdleReaper");
- android.os.Process.setThreadPriority(
- android.os.Process.THREAD_PRIORITY_BACKGROUND);
- synchronized (IdleCache.this) {
- while (check < EMPTY_CHECK_MAX) {
- try {
- IdleCache.this.wait(CHECK_INTERVAL);
- } catch (InterruptedException ex) {
- }
- if (mCount == 0) {
- check++;
- } else {
- check = 0;
- clearIdle();
- }
- }
- mThread = null;
- }
- if (HttpLog.LOGV) {
- HttpLog.v("IdleCache IdleReaper shutdown: cached " + mCached +
- " reused " + mReused);
- mCached = 0;
- mReused = 0;
- }
- }
- }
-}
diff --git a/core/java/android/net/http/LoggingEventHandler.java b/core/java/android/net/http/LoggingEventHandler.java
deleted file mode 100644
index bdafa0b..0000000
--- a/core/java/android/net/http/LoggingEventHandler.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**
- * A test EventHandler: Logs everything received
- */
-
-package android.net.http;
-
-import android.net.http.Headers;
-
-/**
- * {@hide}
- */
-public class LoggingEventHandler implements EventHandler {
-
- public void requestSent() {
- HttpLog.v("LoggingEventHandler:requestSent()");
- }
-
- public void status(int major_version,
- int minor_version,
- int code, /* Status-Code value */
- String reason_phrase) {
- if (HttpLog.LOGV) {
- HttpLog.v("LoggingEventHandler:status() major: " + major_version +
- " minor: " + minor_version +
- " code: " + code +
- " reason: " + reason_phrase);
- }
- }
-
- public void headers(Headers headers) {
- if (HttpLog.LOGV) {
- HttpLog.v("LoggingEventHandler:headers()");
- HttpLog.v(headers.toString());
- }
- }
-
- public void locationChanged(String newLocation, boolean permanent) {
- if (HttpLog.LOGV) {
- HttpLog.v("LoggingEventHandler: locationChanged() " + newLocation +
- " permanent " + permanent);
- }
- }
-
- public void data(byte[] data, int len) {
- if (HttpLog.LOGV) {
- HttpLog.v("LoggingEventHandler: data() " + len + " bytes");
- }
- // HttpLog.v(new String(data, 0, len));
- }
- public void endData() {
- if (HttpLog.LOGV) {
- HttpLog.v("LoggingEventHandler: endData() called");
- }
- }
-
- public void certificate(SslCertificate certificate) {
- if (HttpLog.LOGV) {
- HttpLog.v("LoggingEventHandler: certificate(): " + certificate);
- }
- }
-
- public void error(int id, String description) {
- if (HttpLog.LOGV) {
- HttpLog.v("LoggingEventHandler: error() called Id:" + id +
- " description " + description);
- }
- }
-
- public boolean handleSslErrorRequest(SslError error) {
- if (HttpLog.LOGV) {
- HttpLog.v("LoggingEventHandler: handleSslErrorRequest():" + error);
- }
- // return false so that the caller thread won't wait forever
- return false;
- }
-}
diff --git a/core/java/android/net/http/Request.java b/core/java/android/net/http/Request.java
deleted file mode 100644
index 76d7bb9..0000000
--- a/core/java/android/net/http/Request.java
+++ /dev/null
@@ -1,526 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.http;
-
-import java.io.EOFException;
-import java.io.InputStream;
-import java.io.IOException;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.zip.GZIPInputStream;
-
-import org.apache.http.entity.InputStreamEntity;
-import org.apache.http.Header;
-import org.apache.http.HttpEntity;
-import org.apache.http.HttpEntityEnclosingRequest;
-import org.apache.http.HttpException;
-import org.apache.http.HttpHost;
-import org.apache.http.HttpRequest;
-import org.apache.http.HttpStatus;
-import org.apache.http.ParseException;
-import org.apache.http.ProtocolVersion;
-
-import org.apache.http.StatusLine;
-import org.apache.http.message.BasicHttpRequest;
-import org.apache.http.message.BasicHttpEntityEnclosingRequest;
-import org.apache.http.protocol.RequestContent;
-
-/**
- * Represents an HTTP request for a given host.
- *
- * {@hide}
- */
-
-class Request {
-
- /** The eventhandler to call as the request progresses */
- EventHandler mEventHandler;
-
- private Connection mConnection;
-
- /** The Apache http request */
- BasicHttpRequest mHttpRequest;
-
- /** The path component of this request */
- String mPath;
-
- /** Host serving this request */
- HttpHost mHost;
-
- /** Set if I'm using a proxy server */
- HttpHost mProxyHost;
-
- /** True if request has been cancelled */
- volatile boolean mCancelled = false;
-
- int mFailCount = 0;
-
- // This will be used to set the Range field if we retry a connection. This
- // is http/1.1 feature.
- private int mReceivedBytes = 0;
-
- private InputStream mBodyProvider;
- private int mBodyLength;
-
- private final static String HOST_HEADER = "Host";
- private final static String ACCEPT_ENCODING_HEADER = "Accept-Encoding";
- private final static String CONTENT_LENGTH_HEADER = "content-length";
-
- /* Used to synchronize waitUntilComplete() requests */
- private final Object mClientResource = new Object();
-
- /** True if loading should be paused **/
- private boolean mLoadingPaused = false;
-
- /**
- * Processor used to set content-length and transfer-encoding
- * headers.
- */
- private static RequestContent requestContentProcessor =
- new RequestContent();
-
- /**
- * Instantiates a new Request.
- * @param method GET/POST/PUT
- * @param host The server that will handle this request
- * @param path path part of URI
- * @param bodyProvider InputStream providing HTTP body, null if none
- * @param bodyLength length of body, must be 0 if bodyProvider is null
- * @param eventHandler request will make progress callbacks on
- * this interface
- * @param headers reqeust headers
- */
- Request(String method, HttpHost host, HttpHost proxyHost, String path,
- InputStream bodyProvider, int bodyLength,
- EventHandler eventHandler,
- Map<String, String> headers) {
- mEventHandler = eventHandler;
- mHost = host;
- mProxyHost = proxyHost;
- mPath = path;
- mBodyProvider = bodyProvider;
- mBodyLength = bodyLength;
-
- if (bodyProvider == null && !"POST".equalsIgnoreCase(method)) {
- mHttpRequest = new BasicHttpRequest(method, getUri());
- } else {
- mHttpRequest = new BasicHttpEntityEnclosingRequest(
- method, getUri());
- // it is ok to have null entity for BasicHttpEntityEnclosingRequest.
- // By using BasicHttpEntityEnclosingRequest, it will set up the
- // correct content-length, content-type and content-encoding.
- if (bodyProvider != null) {
- setBodyProvider(bodyProvider, bodyLength);
- }
- }
- addHeader(HOST_HEADER, getHostPort());
-
- /* FIXME: if webcore will make the root document a
- high-priority request, we can ask for gzip encoding only on
- high priority reqs (saving the trouble for images, etc) */
- addHeader(ACCEPT_ENCODING_HEADER, "gzip");
- addHeaders(headers);
- }
-
- /**
- * @param pause True if the load should be paused.
- */
- synchronized void setLoadingPaused(boolean pause) {
- mLoadingPaused = pause;
-
- // Wake up the paused thread if we're unpausing the load.
- if (!mLoadingPaused) {
- notify();
- }
- }
-
- /**
- * @param connection Request served by this connection
- */
- void setConnection(Connection connection) {
- mConnection = connection;
- }
-
- /* package */ EventHandler getEventHandler() {
- return mEventHandler;
- }
-
- /**
- * Add header represented by given pair to request. Header will
- * be formatted in request as "name: value\r\n".
- * @param name of header
- * @param value of header
- */
- void addHeader(String name, String value) {
- if (name == null) {
- String damage = "Null http header name";
- HttpLog.e(damage);
- throw new NullPointerException(damage);
- }
- if (value == null || value.length() == 0) {
- String damage = "Null or empty value for header \"" + name + "\"";
- HttpLog.e(damage);
- throw new RuntimeException(damage);
- }
- mHttpRequest.addHeader(name, value);
- }
-
- /**
- * Add all headers in given map to this request. This is a helper
- * method: it calls addHeader for each pair in the map.
- */
- void addHeaders(Map<String, String> headers) {
- if (headers == null) {
- return;
- }
-
- Entry<String, String> entry;
- Iterator<Entry<String, String>> i = headers.entrySet().iterator();
- while (i.hasNext()) {
- entry = i.next();
- addHeader(entry.getKey(), entry.getValue());
- }
- }
-
- /**
- * Send the request line and headers
- */
- void sendRequest(AndroidHttpClientConnection httpClientConnection)
- throws HttpException, IOException {
-
- if (mCancelled) return; // don't send cancelled requests
-
- if (HttpLog.LOGV) {
- HttpLog.v("Request.sendRequest() " + mHost.getSchemeName() + "://" + getHostPort());
- // HttpLog.v(mHttpRequest.getRequestLine().toString());
- if (false) {
- Iterator i = mHttpRequest.headerIterator();
- while (i.hasNext()) {
- Header header = (Header)i.next();
- HttpLog.v(header.getName() + ": " + header.getValue());
- }
- }
- }
-
- requestContentProcessor.process(mHttpRequest,
- mConnection.getHttpContext());
- httpClientConnection.sendRequestHeader(mHttpRequest);
- if (mHttpRequest instanceof HttpEntityEnclosingRequest) {
- httpClientConnection.sendRequestEntity(
- (HttpEntityEnclosingRequest) mHttpRequest);
- }
-
- if (HttpLog.LOGV) {
- HttpLog.v("Request.requestSent() " + mHost.getSchemeName() + "://" + getHostPort() + mPath);
- }
- }
-
-
- /**
- * Receive a single http response.
- *
- * @param httpClientConnection the request to receive the response for.
- */
- void readResponse(AndroidHttpClientConnection httpClientConnection)
- throws IOException, ParseException {
-
- if (mCancelled) return; // don't send cancelled requests
-
- StatusLine statusLine = null;
- boolean hasBody = false;
- httpClientConnection.flush();
- int statusCode = 0;
-
- Headers header = new Headers();
- do {
- statusLine = httpClientConnection.parseResponseHeader(header);
- statusCode = statusLine.getStatusCode();
- } while (statusCode < HttpStatus.SC_OK);
- if (HttpLog.LOGV) HttpLog.v(
- "Request.readResponseStatus() " +
- statusLine.toString().length() + " " + statusLine);
-
- ProtocolVersion v = statusLine.getProtocolVersion();
- mEventHandler.status(v.getMajor(), v.getMinor(),
- statusCode, statusLine.getReasonPhrase());
- mEventHandler.headers(header);
- HttpEntity entity = null;
- hasBody = canResponseHaveBody(mHttpRequest, statusCode);
-
- if (hasBody)
- entity = httpClientConnection.receiveResponseEntity(header);
-
- // restrict the range request to the servers claiming that they are
- // accepting ranges in bytes
- boolean supportPartialContent = "bytes".equalsIgnoreCase(header
- .getAcceptRanges());
-
- if (entity != null) {
- InputStream is = entity.getContent();
-
- // process gzip content encoding
- Header contentEncoding = entity.getContentEncoding();
- InputStream nis = null;
- byte[] buf = null;
- int count = 0;
- try {
- if (contentEncoding != null &&
- contentEncoding.getValue().equals("gzip")) {
- nis = new GZIPInputStream(is);
- } else {
- nis = is;
- }
-
- /* accumulate enough data to make it worth pushing it
- * up the stack */
- buf = mConnection.getBuf();
- int len = 0;
- int lowWater = buf.length / 2;
- while (len != -1) {
- synchronized(this) {
- while (mLoadingPaused) {
- // Put this (network loading) thread to sleep if WebCore
- // has asked us to. This can happen with plugins for
- // example, if we are streaming data but the plugin has
- // filled its internal buffers.
- try {
- wait();
- } catch (InterruptedException e) {
- HttpLog.e("Interrupted exception whilst "
- + "network thread paused at WebCore's request."
- + " " + e.getMessage());
- }
- }
- }
-
- len = nis.read(buf, count, buf.length - count);
-
- if (len != -1) {
- count += len;
- if (supportPartialContent) mReceivedBytes += len;
- }
- if (len == -1 || count >= lowWater) {
- if (HttpLog.LOGV) HttpLog.v("Request.readResponse() " + count);
- mEventHandler.data(buf, count);
- count = 0;
- }
- }
- } catch (EOFException e) {
- /* InflaterInputStream throws an EOFException when the
- server truncates gzipped content. Handle this case
- as we do truncated non-gzipped content: no error */
- if (count > 0) {
- // if there is uncommited content, we should commit them
- mEventHandler.data(buf, count);
- }
- if (HttpLog.LOGV) HttpLog.v( "readResponse() handling " + e);
- } catch(IOException e) {
- // don't throw if we have a non-OK status code
- if (statusCode == HttpStatus.SC_OK
- || statusCode == HttpStatus.SC_PARTIAL_CONTENT) {
- if (supportPartialContent && count > 0) {
- // if there is uncommited content, we should commit them
- // as we will continue the request
- mEventHandler.data(buf, count);
- }
- throw e;
- }
- } finally {
- if (nis != null) {
- nis.close();
- }
- }
- }
- mConnection.setCanPersist(entity, statusLine.getProtocolVersion(),
- header.getConnectionType());
- mEventHandler.endData();
- complete();
-
- if (HttpLog.LOGV) HttpLog.v("Request.readResponse(): done " +
- mHost.getSchemeName() + "://" + getHostPort() + mPath);
- }
-
- /**
- * Data will not be sent to or received from server after cancel()
- * call. Does not close connection--use close() below for that.
- *
- * Called by RequestHandle from non-network thread
- */
- synchronized void cancel() {
- if (HttpLog.LOGV) {
- HttpLog.v("Request.cancel(): " + getUri());
- }
-
- // Ensure that the network thread is not blocked by a hanging request from WebCore to
- // pause the load.
- mLoadingPaused = false;
- notify();
-
- mCancelled = true;
- if (mConnection != null) {
- mConnection.cancel();
- }
- }
-
- String getHostPort() {
- String myScheme = mHost.getSchemeName();
- int myPort = mHost.getPort();
-
- // Only send port when we must... many servers can't deal with it
- if (myPort != 80 && myScheme.equals("http") ||
- myPort != 443 && myScheme.equals("https")) {
- return mHost.toHostString();
- } else {
- return mHost.getHostName();
- }
- }
-
- String getUri() {
- if (mProxyHost == null ||
- mHost.getSchemeName().equals("https")) {
- return mPath;
- }
- return mHost.getSchemeName() + "://" + getHostPort() + mPath;
- }
-
- /**
- * for debugging
- */
- public String toString() {
- return mPath;
- }
-
-
- /**
- * If this request has been sent once and failed, it must be reset
- * before it can be sent again.
- */
- void reset() {
- /* clear content-length header */
- mHttpRequest.removeHeaders(CONTENT_LENGTH_HEADER);
-
- if (mBodyProvider != null) {
- try {
- mBodyProvider.reset();
- } catch (IOException ex) {
- if (HttpLog.LOGV) HttpLog.v(
- "failed to reset body provider " +
- getUri());
- }
- setBodyProvider(mBodyProvider, mBodyLength);
- }
-
- if (mReceivedBytes > 0) {
- // reset the fail count as we continue the request
- mFailCount = 0;
- // set the "Range" header to indicate that the retry will continue
- // instead of restarting the request
- HttpLog.v("*** Request.reset() to range:" + mReceivedBytes);
- mHttpRequest.setHeader("Range", "bytes=" + mReceivedBytes + "-");
- }
- }
-
- /**
- * Pause thread request completes. Used for synchronous requests,
- * and testing
- */
- void waitUntilComplete() {
- synchronized (mClientResource) {
- try {
- if (HttpLog.LOGV) HttpLog.v("Request.waitUntilComplete()");
- mClientResource.wait();
- if (HttpLog.LOGV) HttpLog.v("Request.waitUntilComplete() done waiting");
- } catch (InterruptedException e) {
- }
- }
- }
-
- void complete() {
- synchronized (mClientResource) {
- mClientResource.notifyAll();
- }
- }
-
- /**
- * Decide whether a response comes with an entity.
- * The implementation in this class is based on RFC 2616.
- * Unknown methods and response codes are supposed to
- * indicate responses with an entity.
- * <br/>
- * Derived executors can override this method to handle
- * methods and response codes not specified in RFC 2616.
- *
- * @param request the request, to obtain the executed method
- * @param response the response, to obtain the status code
- */
-
- private static boolean canResponseHaveBody(final HttpRequest request,
- final int status) {
-
- if ("HEAD".equalsIgnoreCase(request.getRequestLine().getMethod())) {
- return false;
- }
- return status >= HttpStatus.SC_OK
- && status != HttpStatus.SC_NO_CONTENT
- && status != HttpStatus.SC_NOT_MODIFIED;
- }
-
- /**
- * Supply an InputStream that provides the body of a request. It's
- * not great that the caller must also provide the length of the data
- * returned by that InputStream, but the client needs to know up
- * front, and I'm not sure how to get this out of the InputStream
- * itself without a costly readthrough. I'm not sure skip() would
- * do what we want. If you know a better way, please let me know.
- */
- private void setBodyProvider(InputStream bodyProvider, int bodyLength) {
- if (!bodyProvider.markSupported()) {
- throw new IllegalArgumentException(
- "bodyProvider must support mark()");
- }
- // Mark beginning of stream
- bodyProvider.mark(Integer.MAX_VALUE);
-
- ((BasicHttpEntityEnclosingRequest)mHttpRequest).setEntity(
- new InputStreamEntity(bodyProvider, bodyLength));
- }
-
-
- /**
- * Handles SSL error(s) on the way down from the user (the user
- * has already provided their feedback).
- */
- public void handleSslErrorResponse(boolean proceed) {
- HttpsConnection connection = (HttpsConnection)(mConnection);
- if (connection != null) {
- connection.restartConnection(proceed);
- }
- }
-
- /**
- * Helper: calls error() on eventhandler with appropriate message
- * This should not be called before the mConnection is set.
- */
- void error(int errorId, int resourceId) {
- mEventHandler.error(
- errorId,
- mConnection.mContext.getText(
- resourceId).toString());
- }
-
-}
diff --git a/core/java/android/net/http/RequestFeeder.java b/core/java/android/net/http/RequestFeeder.java
deleted file mode 100644
index 34ca267..0000000
--- a/core/java/android/net/http/RequestFeeder.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**
- * Supplies Requests to a Connection
- */
-
-package android.net.http;
-
-import org.apache.http.HttpHost;
-
-/**
- * {@hide}
- */
-interface RequestFeeder {
-
- Request getRequest();
- Request getRequest(HttpHost host);
-
- /**
- * @return true if a request for this host is available
- */
- boolean haveRequest(HttpHost host);
-
- /**
- * Put request back on head of queue
- */
- void requeueRequest(Request request);
-}
diff --git a/core/java/android/net/http/RequestHandle.java b/core/java/android/net/http/RequestHandle.java
deleted file mode 100644
index f23f69c..0000000
--- a/core/java/android/net/http/RequestHandle.java
+++ /dev/null
@@ -1,466 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.http;
-
-import android.net.ParseException;
-import android.net.WebAddress;
-import junit.framework.Assert;
-import android.webkit.CookieManager;
-
-import org.apache.commons.codec.binary.Base64;
-
-import java.io.InputStream;
-import java.lang.Math;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Random;
-
-/**
- * RequestHandle: handles a request session that may include multiple
- * redirects, HTTP authentication requests, etc.
- *
- * {@hide}
- */
-public class RequestHandle {
-
- private String mUrl;
- private WebAddress mUri;
- private String mMethod;
- private Map<String, String> mHeaders;
- private RequestQueue mRequestQueue;
- private Request mRequest;
- private InputStream mBodyProvider;
- private int mBodyLength;
- private int mRedirectCount = 0;
- // Used only with synchronous requests.
- private Connection mConnection;
-
- private final static String AUTHORIZATION_HEADER = "Authorization";
- private final static String PROXY_AUTHORIZATION_HEADER = "Proxy-Authorization";
-
- public final static int MAX_REDIRECT_COUNT = 16;
-
- /**
- * Creates a new request session.
- */
- public RequestHandle(RequestQueue requestQueue, String url, WebAddress uri,
- String method, Map<String, String> headers,
- InputStream bodyProvider, int bodyLength, Request request) {
-
- if (headers == null) {
- headers = new HashMap<String, String>();
- }
- mHeaders = headers;
- mBodyProvider = bodyProvider;
- mBodyLength = bodyLength;
- mMethod = method == null? "GET" : method;
-
- mUrl = url;
- mUri = uri;
-
- mRequestQueue = requestQueue;
-
- mRequest = request;
- }
-
- /**
- * Creates a new request session with a given Connection. This connection
- * is used during a synchronous load to handle this request.
- */
- public RequestHandle(RequestQueue requestQueue, String url, WebAddress uri,
- String method, Map<String, String> headers,
- InputStream bodyProvider, int bodyLength, Request request,
- Connection conn) {
- this(requestQueue, url, uri, method, headers, bodyProvider, bodyLength,
- request);
- mConnection = conn;
- }
-
- /**
- * Cancels this request
- */
- public void cancel() {
- if (mRequest != null) {
- mRequest.cancel();
- }
- }
-
- /**
- * Pauses the loading of this request. For example, called from the WebCore thread
- * when the plugin can take no more data.
- */
- public void pauseRequest(boolean pause) {
- if (mRequest != null) {
- mRequest.setLoadingPaused(pause);
- }
- }
-
- /**
- * Handles SSL error(s) on the way down from the user (the user
- * has already provided their feedback).
- */
- public void handleSslErrorResponse(boolean proceed) {
- if (mRequest != null) {
- mRequest.handleSslErrorResponse(proceed);
- }
- }
-
- /**
- * @return true if we've hit the max redirect count
- */
- public boolean isRedirectMax() {
- return mRedirectCount >= MAX_REDIRECT_COUNT;
- }
-
- public int getRedirectCount() {
- return mRedirectCount;
- }
-
- public void setRedirectCount(int count) {
- mRedirectCount = count;
- }
-
- /**
- * Create and queue a redirect request.
- *
- * @param redirectTo URL to redirect to
- * @param statusCode HTTP status code returned from original request
- * @param cacheHeaders Cache header for redirect URL
- * @return true if setup succeeds, false otherwise (redirect loop
- * count exceeded, body provider unable to rewind on 307 redirect)
- */
- public boolean setupRedirect(String redirectTo, int statusCode,
- Map<String, String> cacheHeaders) {
- if (HttpLog.LOGV) {
- HttpLog.v("RequestHandle.setupRedirect(): redirectCount " +
- mRedirectCount);
- }
-
- // be careful and remove authentication headers, if any
- mHeaders.remove(AUTHORIZATION_HEADER);
- mHeaders.remove(PROXY_AUTHORIZATION_HEADER);
-
- if (++mRedirectCount == MAX_REDIRECT_COUNT) {
- // Way too many redirects -- fail out
- if (HttpLog.LOGV) HttpLog.v(
- "RequestHandle.setupRedirect(): too many redirects " +
- mRequest);
- mRequest.error(EventHandler.ERROR_REDIRECT_LOOP,
- com.android.internal.R.string.httpErrorRedirectLoop);
- return false;
- }
-
- if (mUrl.startsWith("https:") && redirectTo.startsWith("http:")) {
- // implement http://www.w3.org/Protocols/rfc2616/rfc2616-sec15.html#sec15.1.3
- if (HttpLog.LOGV) {
- HttpLog.v("blowing away the referer on an https -> http redirect");
- }
- mHeaders.remove("Referer");
- }
-
- mUrl = redirectTo;
- try {
- mUri = new WebAddress(mUrl);
- } catch (ParseException e) {
- e.printStackTrace();
- }
-
- // update the "Cookie" header based on the redirected url
- mHeaders.remove("Cookie");
- String cookie = CookieManager.getInstance().getCookie(mUri);
- if (cookie != null && cookie.length() > 0) {
- mHeaders.put("Cookie", cookie);
- }
-
- if ((statusCode == 302 || statusCode == 303) && mMethod.equals("POST")) {
- if (HttpLog.LOGV) {
- HttpLog.v("replacing POST with GET on redirect to " + redirectTo);
- }
- mMethod = "GET";
- }
- /* Only repost content on a 307. If 307, reset the body
- provider so we can replay the body */
- if (statusCode == 307) {
- try {
- if (mBodyProvider != null) mBodyProvider.reset();
- } catch (java.io.IOException ex) {
- if (HttpLog.LOGV) {
- HttpLog.v("setupRedirect() failed to reset body provider");
- }
- return false;
- }
-
- } else {
- mHeaders.remove("Content-Type");
- mBodyProvider = null;
- }
-
- // Update the cache headers for this URL
- mHeaders.putAll(cacheHeaders);
-
- createAndQueueNewRequest();
- return true;
- }
-
- /**
- * Create and queue an HTTP authentication-response (basic) request.
- */
- public void setupBasicAuthResponse(boolean isProxy, String username, String password) {
- String response = computeBasicAuthResponse(username, password);
- if (HttpLog.LOGV) {
- HttpLog.v("setupBasicAuthResponse(): response: " + response);
- }
- mHeaders.put(authorizationHeader(isProxy), "Basic " + response);
- setupAuthResponse();
- }
-
- /**
- * Create and queue an HTTP authentication-response (digest) request.
- */
- public void setupDigestAuthResponse(boolean isProxy,
- String username,
- String password,
- String realm,
- String nonce,
- String QOP,
- String algorithm,
- String opaque) {
-
- String response = computeDigestAuthResponse(
- username, password, realm, nonce, QOP, algorithm, opaque);
- if (HttpLog.LOGV) {
- HttpLog.v("setupDigestAuthResponse(): response: " + response);
- }
- mHeaders.put(authorizationHeader(isProxy), "Digest " + response);
- setupAuthResponse();
- }
-
- private void setupAuthResponse() {
- try {
- if (mBodyProvider != null) mBodyProvider.reset();
- } catch (java.io.IOException ex) {
- if (HttpLog.LOGV) {
- HttpLog.v("setupAuthResponse() failed to reset body provider");
- }
- }
- createAndQueueNewRequest();
- }
-
- /**
- * @return HTTP request method (GET, PUT, etc).
- */
- public String getMethod() {
- return mMethod;
- }
-
- /**
- * @return Basic-scheme authentication response: BASE64(username:password).
- */
- public static String computeBasicAuthResponse(String username, String password) {
- Assert.assertNotNull(username);
- Assert.assertNotNull(password);
-
- // encode username:password to base64
- return new String(Base64.encodeBase64((username + ':' + password).getBytes()));
- }
-
- public void waitUntilComplete() {
- mRequest.waitUntilComplete();
- }
-
- public void processRequest() {
- if (mConnection != null) {
- mConnection.processRequests(mRequest);
- }
- }
-
- /**
- * @return Digest-scheme authentication response.
- */
- private String computeDigestAuthResponse(String username,
- String password,
- String realm,
- String nonce,
- String QOP,
- String algorithm,
- String opaque) {
-
- Assert.assertNotNull(username);
- Assert.assertNotNull(password);
- Assert.assertNotNull(realm);
-
- String A1 = username + ":" + realm + ":" + password;
- String A2 = mMethod + ":" + mUrl;
-
- // because we do not preemptively send authorization headers, nc is always 1
- String nc = "00000001";
- String cnonce = computeCnonce();
- String digest = computeDigest(A1, A2, nonce, QOP, nc, cnonce);
-
- String response = "";
- response += "username=" + doubleQuote(username) + ", ";
- response += "realm=" + doubleQuote(realm) + ", ";
- response += "nonce=" + doubleQuote(nonce) + ", ";
- response += "uri=" + doubleQuote(mUrl) + ", ";
- response += "response=" + doubleQuote(digest) ;
-
- if (opaque != null) {
- response += ", opaque=" + doubleQuote(opaque);
- }
-
- if (algorithm != null) {
- response += ", algorithm=" + algorithm;
- }
-
- if (QOP != null) {
- response += ", qop=" + QOP + ", nc=" + nc + ", cnonce=" + doubleQuote(cnonce);
- }
-
- return response;
- }
-
- /**
- * @return The right authorization header (dependeing on whether it is a proxy or not).
- */
- public static String authorizationHeader(boolean isProxy) {
- if (!isProxy) {
- return AUTHORIZATION_HEADER;
- } else {
- return PROXY_AUTHORIZATION_HEADER;
- }
- }
-
- /**
- * @return Double-quoted MD5 digest.
- */
- private String computeDigest(
- String A1, String A2, String nonce, String QOP, String nc, String cnonce) {
- if (HttpLog.LOGV) {
- HttpLog.v("computeDigest(): QOP: " + QOP);
- }
-
- if (QOP == null) {
- return KD(H(A1), nonce + ":" + H(A2));
- } else {
- if (QOP.equalsIgnoreCase("auth")) {
- return KD(H(A1), nonce + ":" + nc + ":" + cnonce + ":" + QOP + ":" + H(A2));
- }
- }
-
- return null;
- }
-
- /**
- * @return MD5 hash of concat(secret, ":", data).
- */
- private String KD(String secret, String data) {
- return H(secret + ":" + data);
- }
-
- /**
- * @return MD5 hash of param.
- */
- private String H(String param) {
- if (param != null) {
- try {
- MessageDigest md5 = MessageDigest.getInstance("MD5");
-
- byte[] d = md5.digest(param.getBytes());
- if (d != null) {
- return bufferToHex(d);
- }
- } catch (NoSuchAlgorithmException e) {
- throw new RuntimeException(e);
- }
- }
-
- return null;
- }
-
- /**
- * @return HEX buffer representation.
- */
- private String bufferToHex(byte[] buffer) {
- final char hexChars[] =
- { '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f' };
-
- if (buffer != null) {
- int length = buffer.length;
- if (length > 0) {
- StringBuilder hex = new StringBuilder(2 * length);
-
- for (int i = 0; i < length; ++i) {
- byte l = (byte) (buffer[i] & 0x0F);
- byte h = (byte)((buffer[i] & 0xF0) >> 4);
-
- hex.append(hexChars[h]);
- hex.append(hexChars[l]);
- }
-
- return hex.toString();
- } else {
- return "";
- }
- }
-
- return null;
- }
-
- /**
- * Computes a random cnonce value based on the current time.
- */
- private String computeCnonce() {
- Random rand = new Random();
- int nextInt = rand.nextInt();
- nextInt = (nextInt == Integer.MIN_VALUE) ?
- Integer.MAX_VALUE : Math.abs(nextInt);
- return Integer.toString(nextInt, 16);
- }
-
- /**
- * "Double-quotes" the argument.
- */
- private String doubleQuote(String param) {
- if (param != null) {
- return "\"" + param + "\"";
- }
-
- return null;
- }
-
- /**
- * Creates and queues new request.
- */
- private void createAndQueueNewRequest() {
- // mConnection is non-null if and only if the requests are synchronous.
- if (mConnection != null) {
- RequestHandle newHandle = mRequestQueue.queueSynchronousRequest(
- mUrl, mUri, mMethod, mHeaders, mRequest.mEventHandler,
- mBodyProvider, mBodyLength);
- mRequest = newHandle.mRequest;
- mConnection = newHandle.mConnection;
- newHandle.processRequest();
- return;
- }
- mRequest = mRequestQueue.queueRequest(
- mUrl, mUri, mMethod, mHeaders, mRequest.mEventHandler,
- mBodyProvider,
- mBodyLength).mRequest;
- }
-}
diff --git a/core/java/android/net/http/RequestQueue.java b/core/java/android/net/http/RequestQueue.java
deleted file mode 100644
index 7d2da1b..0000000
--- a/core/java/android/net/http/RequestQueue.java
+++ /dev/null
@@ -1,542 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**
- * High level HTTP Interface
- * Queues requests as necessary
- */
-
-package android.net.http;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.net.ConnectivityManager;
-import android.net.NetworkInfo;
-import android.net.Proxy;
-import android.net.WebAddress;
-import android.util.Log;
-
-import java.io.InputStream;
-import java.util.Iterator;
-import java.util.LinkedHashMap;
-import java.util.LinkedList;
-import java.util.ListIterator;
-import java.util.Map;
-
-import org.apache.http.HttpHost;
-
-/**
- * {@hide}
- */
-public class RequestQueue implements RequestFeeder {
-
-
- /**
- * Requests, indexed by HttpHost (scheme, host, port)
- */
- private final LinkedHashMap<HttpHost, LinkedList<Request>> mPending;
- private final Context mContext;
- private final ActivePool mActivePool;
- private final ConnectivityManager mConnectivityManager;
-
- private HttpHost mProxyHost = null;
- private BroadcastReceiver mProxyChangeReceiver;
-
- /* default simultaneous connection count */
- private static final int CONNECTION_COUNT = 4;
-
- /**
- * This class maintains active connection threads
- */
- class ActivePool implements ConnectionManager {
- /** Threads used to process requests */
- ConnectionThread[] mThreads;
-
- IdleCache mIdleCache;
-
- private int mTotalRequest;
- private int mTotalConnection;
- private int mConnectionCount;
-
- ActivePool(int connectionCount) {
- mIdleCache = new IdleCache();
- mConnectionCount = connectionCount;
- mThreads = new ConnectionThread[mConnectionCount];
-
- for (int i = 0; i < mConnectionCount; i++) {
- mThreads[i] = new ConnectionThread(
- mContext, i, this, RequestQueue.this);
- }
- }
-
- void startup() {
- for (int i = 0; i < mConnectionCount; i++) {
- mThreads[i].start();
- }
- }
-
- void shutdown() {
- for (int i = 0; i < mConnectionCount; i++) {
- mThreads[i].requestStop();
- }
- }
-
- void startConnectionThread() {
- synchronized (RequestQueue.this) {
- RequestQueue.this.notify();
- }
- }
-
- public void startTiming() {
- for (int i = 0; i < mConnectionCount; i++) {
- ConnectionThread rt = mThreads[i];
- rt.mCurrentThreadTime = -1;
- rt.mTotalThreadTime = 0;
- }
- mTotalRequest = 0;
- mTotalConnection = 0;
- }
-
- public void stopTiming() {
- int totalTime = 0;
- for (int i = 0; i < mConnectionCount; i++) {
- ConnectionThread rt = mThreads[i];
- if (rt.mCurrentThreadTime != -1) {
- totalTime += rt.mTotalThreadTime;
- }
- rt.mCurrentThreadTime = 0;
- }
- Log.d("Http", "Http thread used " + totalTime + " ms " + " for "
- + mTotalRequest + " requests and " + mTotalConnection
- + " new connections");
- }
-
- void logState() {
- StringBuilder dump = new StringBuilder();
- for (int i = 0; i < mConnectionCount; i++) {
- dump.append(mThreads[i] + "\n");
- }
- HttpLog.v(dump.toString());
- }
-
-
- public HttpHost getProxyHost() {
- return mProxyHost;
- }
-
- /**
- * Turns off persistence on all live connections
- */
- void disablePersistence() {
- for (int i = 0; i < mConnectionCount; i++) {
- Connection connection = mThreads[i].mConnection;
- if (connection != null) connection.setCanPersist(false);
- }
- mIdleCache.clear();
- }
-
- /* Linear lookup -- okay for small thread counts. Might use
- private HashMap<HttpHost, LinkedList<ConnectionThread>> mActiveMap;
- if this turns out to be a hotspot */
- ConnectionThread getThread(HttpHost host) {
- synchronized(RequestQueue.this) {
- for (int i = 0; i < mThreads.length; i++) {
- ConnectionThread ct = mThreads[i];
- Connection connection = ct.mConnection;
- if (connection != null && connection.mHost.equals(host)) {
- return ct;
- }
- }
- }
- return null;
- }
-
- public Connection getConnection(Context context, HttpHost host) {
- host = RequestQueue.this.determineHost(host);
- Connection con = mIdleCache.getConnection(host);
- if (con == null) {
- mTotalConnection++;
- con = Connection.getConnection(mContext, host, mProxyHost,
- RequestQueue.this);
- }
- return con;
- }
- public boolean recycleConnection(Connection connection) {
- return mIdleCache.cacheConnection(connection.getHost(), connection);
- }
-
- }
-
- /**
- * A RequestQueue class instance maintains a set of queued
- * requests. It orders them, makes the requests against HTTP
- * servers, and makes callbacks to supplied eventHandlers as data
- * is read. It supports request prioritization, connection reuse
- * and pipelining.
- *
- * @param context application context
- */
- public RequestQueue(Context context) {
- this(context, CONNECTION_COUNT);
- }
-
- /**
- * A RequestQueue class instance maintains a set of queued
- * requests. It orders them, makes the requests against HTTP
- * servers, and makes callbacks to supplied eventHandlers as data
- * is read. It supports request prioritization, connection reuse
- * and pipelining.
- *
- * @param context application context
- * @param connectionCount The number of simultaneous connections
- */
- public RequestQueue(Context context, int connectionCount) {
- mContext = context;
-
- mPending = new LinkedHashMap<HttpHost, LinkedList<Request>>(32);
-
- mActivePool = new ActivePool(connectionCount);
- mActivePool.startup();
-
- mConnectivityManager = (ConnectivityManager)
- context.getSystemService(Context.CONNECTIVITY_SERVICE);
- }
-
- /**
- * Enables data state and proxy tracking
- */
- public synchronized void enablePlatformNotifications() {
- if (HttpLog.LOGV) HttpLog.v("RequestQueue.enablePlatformNotifications() network");
-
- if (mProxyChangeReceiver == null) {
- mProxyChangeReceiver =
- new BroadcastReceiver() {
- @Override
- public void onReceive(Context ctx, Intent intent) {
- setProxyConfig();
- }
- };
- mContext.registerReceiver(mProxyChangeReceiver,
- new IntentFilter(Proxy.PROXY_CHANGE_ACTION));
- }
- // we need to resample the current proxy setup
- setProxyConfig();
- }
-
- /**
- * If platform notifications have been enabled, call this method
- * to disable before destroying RequestQueue
- */
- public synchronized void disablePlatformNotifications() {
- if (HttpLog.LOGV) HttpLog.v("RequestQueue.disablePlatformNotifications() network");
-
- if (mProxyChangeReceiver != null) {
- mContext.unregisterReceiver(mProxyChangeReceiver);
- mProxyChangeReceiver = null;
- }
- }
-
- /**
- * Because our IntentReceiver can run within a different thread,
- * synchronize setting the proxy
- */
- private synchronized void setProxyConfig() {
- NetworkInfo info = mConnectivityManager.getActiveNetworkInfo();
- if (info != null && info.getType() == ConnectivityManager.TYPE_WIFI) {
- mProxyHost = null;
- } else {
- String host = Proxy.getHost(mContext);
- if (HttpLog.LOGV) HttpLog.v("RequestQueue.setProxyConfig " + host);
- if (host == null) {
- mProxyHost = null;
- } else {
- mActivePool.disablePersistence();
- mProxyHost = new HttpHost(host, Proxy.getPort(mContext), "http");
- }
- }
- }
-
- /**
- * used by webkit
- * @return proxy host if set, null otherwise
- */
- public HttpHost getProxyHost() {
- return mProxyHost;
- }
-
- /**
- * Queues an HTTP request
- * @param url The url to load.
- * @param method "GET" or "POST."
- * @param headers A hashmap of http headers.
- * @param eventHandler The event handler for handling returned
- * data. Callbacks will be made on the supplied instance.
- * @param bodyProvider InputStream providing HTTP body, null if none
- * @param bodyLength length of body, must be 0 if bodyProvider is null
- */
- public RequestHandle queueRequest(
- String url, String method,
- Map<String, String> headers, EventHandler eventHandler,
- InputStream bodyProvider, int bodyLength) {
- WebAddress uri = new WebAddress(url);
- return queueRequest(url, uri, method, headers, eventHandler,
- bodyProvider, bodyLength);
- }
-
- /**
- * Queues an HTTP request
- * @param url The url to load.
- * @param uri The uri of the url to load.
- * @param method "GET" or "POST."
- * @param headers A hashmap of http headers.
- * @param eventHandler The event handler for handling returned
- * data. Callbacks will be made on the supplied instance.
- * @param bodyProvider InputStream providing HTTP body, null if none
- * @param bodyLength length of body, must be 0 if bodyProvider is null
- */
- public RequestHandle queueRequest(
- String url, WebAddress uri, String method, Map<String, String> headers,
- EventHandler eventHandler,
- InputStream bodyProvider, int bodyLength) {
-
- if (HttpLog.LOGV) HttpLog.v("RequestQueue.queueRequest " + uri);
-
- // Ensure there is an eventHandler set
- if (eventHandler == null) {
- eventHandler = new LoggingEventHandler();
- }
-
- /* Create and queue request */
- Request req;
- HttpHost httpHost = new HttpHost(uri.getHost(), uri.getPort(), uri.getScheme());
-
- // set up request
- req = new Request(method, httpHost, mProxyHost, uri.getPath(), bodyProvider,
- bodyLength, eventHandler, headers);
-
- queueRequest(req, false);
-
- mActivePool.mTotalRequest++;
-
- // dump();
- mActivePool.startConnectionThread();
-
- return new RequestHandle(
- this, url, uri, method, headers, bodyProvider, bodyLength,
- req);
- }
-
- private static class SyncFeeder implements RequestFeeder {
- // This is used in the case where the request fails and needs to be
- // requeued into the RequestFeeder.
- private Request mRequest;
- SyncFeeder() {
- }
- public Request getRequest() {
- Request r = mRequest;
- mRequest = null;
- return r;
- }
- public Request getRequest(HttpHost host) {
- return getRequest();
- }
- public boolean haveRequest(HttpHost host) {
- return mRequest != null;
- }
- public void requeueRequest(Request r) {
- mRequest = r;
- }
- }
-
- public RequestHandle queueSynchronousRequest(String url, WebAddress uri,
- String method, Map<String, String> headers,
- EventHandler eventHandler, InputStream bodyProvider,
- int bodyLength) {
- if (HttpLog.LOGV) {
- HttpLog.v("RequestQueue.dispatchSynchronousRequest " + uri);
- }
-
- HttpHost host = new HttpHost(uri.getHost(), uri.getPort(), uri.getScheme());
-
- Request req = new Request(method, host, mProxyHost, uri.getPath(),
- bodyProvider, bodyLength, eventHandler, headers);
-
- // Open a new connection that uses our special RequestFeeder
- // implementation.
- host = determineHost(host);
- Connection conn = Connection.getConnection(mContext, host, mProxyHost,
- new SyncFeeder());
-
- // TODO: I would like to process the request here but LoadListener
- // needs a RequestHandle to process some messages.
- return new RequestHandle(this, url, uri, method, headers, bodyProvider,
- bodyLength, req, conn);
-
- }
-
- // Chooses between the proxy and the request's host.
- private HttpHost determineHost(HttpHost host) {
- // There used to be a comment in ConnectionThread about t-mob's proxy
- // being really bad about https. But, HttpsConnection actually looks
- // for a proxy and connects through it anyway. I think that this check
- // is still valid because if a site is https, we will use
- // HttpsConnection rather than HttpConnection if the proxy address is
- // not secure.
- return (mProxyHost == null || "https".equals(host.getSchemeName()))
- ? host : mProxyHost;
- }
-
- /**
- * @return true iff there are any non-active requests pending
- */
- synchronized boolean requestsPending() {
- return !mPending.isEmpty();
- }
-
-
- /**
- * debug tool: prints request queue to log
- */
- synchronized void dump() {
- HttpLog.v("dump()");
- StringBuilder dump = new StringBuilder();
- int count = 0;
- Iterator<Map.Entry<HttpHost, LinkedList<Request>>> iter;
-
- // mActivePool.log(dump);
-
- if (!mPending.isEmpty()) {
- iter = mPending.entrySet().iterator();
- while (iter.hasNext()) {
- Map.Entry<HttpHost, LinkedList<Request>> entry = iter.next();
- String hostName = entry.getKey().getHostName();
- StringBuilder line = new StringBuilder("p" + count++ + " " + hostName + " ");
-
- LinkedList<Request> reqList = entry.getValue();
- ListIterator reqIter = reqList.listIterator(0);
- while (iter.hasNext()) {
- Request request = (Request)iter.next();
- line.append(request + " ");
- }
- dump.append(line);
- dump.append("\n");
- }
- }
- HttpLog.v(dump.toString());
- }
-
- /*
- * RequestFeeder implementation
- */
- public synchronized Request getRequest() {
- Request ret = null;
-
- if (!mPending.isEmpty()) {
- ret = removeFirst(mPending);
- }
- if (HttpLog.LOGV) HttpLog.v("RequestQueue.getRequest() => " + ret);
- return ret;
- }
-
- /**
- * @return a request for given host if possible
- */
- public synchronized Request getRequest(HttpHost host) {
- Request ret = null;
-
- if (mPending.containsKey(host)) {
- LinkedList<Request> reqList = mPending.get(host);
- ret = reqList.removeFirst();
- if (reqList.isEmpty()) {
- mPending.remove(host);
- }
- }
- if (HttpLog.LOGV) HttpLog.v("RequestQueue.getRequest(" + host + ") => " + ret);
- return ret;
- }
-
- /**
- * @return true if a request for this host is available
- */
- public synchronized boolean haveRequest(HttpHost host) {
- return mPending.containsKey(host);
- }
-
- /**
- * Put request back on head of queue
- */
- public void requeueRequest(Request request) {
- queueRequest(request, true);
- }
-
- /**
- * This must be called to cleanly shutdown RequestQueue
- */
- public void shutdown() {
- mActivePool.shutdown();
- }
-
- protected synchronized void queueRequest(Request request, boolean head) {
- HttpHost host = request.mProxyHost == null ? request.mHost : request.mProxyHost;
- LinkedList<Request> reqList;
- if (mPending.containsKey(host)) {
- reqList = mPending.get(host);
- } else {
- reqList = new LinkedList<Request>();
- mPending.put(host, reqList);
- }
- if (head) {
- reqList.addFirst(request);
- } else {
- reqList.add(request);
- }
- }
-
-
- public void startTiming() {
- mActivePool.startTiming();
- }
-
- public void stopTiming() {
- mActivePool.stopTiming();
- }
-
- /* helper */
- private Request removeFirst(LinkedHashMap<HttpHost, LinkedList<Request>> requestQueue) {
- Request ret = null;
- Iterator<Map.Entry<HttpHost, LinkedList<Request>>> iter = requestQueue.entrySet().iterator();
- if (iter.hasNext()) {
- Map.Entry<HttpHost, LinkedList<Request>> entry = iter.next();
- LinkedList<Request> reqList = entry.getValue();
- ret = reqList.removeFirst();
- if (reqList.isEmpty()) {
- requestQueue.remove(entry.getKey());
- }
- }
- return ret;
- }
-
- /**
- * This interface is exposed to each connection
- */
- interface ConnectionManager {
- HttpHost getProxyHost();
- Connection getConnection(Context context, HttpHost host);
- boolean recycleConnection(Connection connection);
- }
-}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 250e80f..15acaad 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -51,14 +51,21 @@ import android.os.Build.VERSION_CODES;
import android.speech.tts.TextToSpeech;
import android.text.TextUtils;
import android.util.AndroidException;
+import android.util.ArrayMap;
+import android.util.ArraySet;
import android.util.Log;
+import com.android.internal.util.ArrayUtils;
import com.android.internal.widget.ILockSettings;
import java.net.URISyntaxException;
+import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Pattern;
/**
* The Settings provider contains global system-level device preferences.
@@ -1192,6 +1199,11 @@ public final class Settings {
public static final class System extends NameValueTable {
public static final String SYS_PROP_SETTING_VERSION = "sys.settings_system_version";
+ /** @hide */
+ public static interface Validator {
+ public boolean validate(String value);
+ }
+
/**
* The content:// style URL for this table
*/
@@ -1294,13 +1306,56 @@ public final class Settings {
MOVED_TO_GLOBAL.add(Settings.Global.CERT_PIN_UPDATE_METADATA_URL);
}
+ private static final Validator sBooleanValidator =
+ new DiscreteValueValidator(new String[] {"0", "1"});
+
+ private static final Validator sNonNegativeIntegerValidator = new Validator() {
+ @Override
+ public boolean validate(String value) {
+ try {
+ return Integer.parseInt(value) >= 0;
+ } catch (NumberFormatException e) {
+ return false;
+ }
+ }
+ };
+
+ private static final Validator sVolumeValidator =
+ new InclusiveFloatRangeValidator(0, 1);
+
+ private static final Validator sUriValidator = new Validator() {
+ @Override
+ public boolean validate(String value) {
+ try {
+ Uri.decode(value);
+ return true;
+ } catch (IllegalArgumentException e) {
+ return false;
+ }
+ }
+ };
+
+ private static final Validator sLenientIpAddressValidator = new Validator() {
+ private static final int MAX_IPV6_LENGTH = 45;
+
+ @Override
+ public boolean validate(String value) {
+ return value.length() <= MAX_IPV6_LENGTH;
+ }
+ };
+
/** @hide */
- public static void getMovedKeys(HashSet<String> outKeySet) {
+ public static void getMovedToGlobalSettings(Set<String> outKeySet) {
outKeySet.addAll(MOVED_TO_GLOBAL);
outKeySet.addAll(MOVED_TO_SECURE_THEN_GLOBAL);
}
/** @hide */
+ public static void getMovedToSecureSettings(Set<String> outKeySet) {
+ outKeySet.addAll(MOVED_TO_SECURE);
+ }
+
+ /** @hide */
public static void getNonLegacyMovedKeys(HashSet<String> outKeySet) {
outKeySet.addAll(MOVED_TO_GLOBAL);
}
@@ -1723,6 +1778,56 @@ public final class Settings {
putIntForUser(cr, SHOW_GTALK_SERVICE_STATUS, flag ? 1 : 0, userHandle);
}
+ private static final class DiscreteValueValidator implements Validator {
+ private final String[] mValues;
+
+ public DiscreteValueValidator(String[] values) {
+ mValues = values;
+ }
+
+ public boolean validate(String value) {
+ return ArrayUtils.contains(mValues, value);
+ }
+ }
+
+ private static final class InclusiveIntegerRangeValidator implements Validator {
+ private final int mMin;
+ private final int mMax;
+
+ public InclusiveIntegerRangeValidator(int min, int max) {
+ mMin = min;
+ mMax = max;
+ }
+
+ public boolean validate(String value) {
+ try {
+ final int intValue = Integer.parseInt(value);
+ return intValue >= mMin && intValue <= mMax;
+ } catch (NumberFormatException e) {
+ return false;
+ }
+ }
+ }
+
+ private static final class InclusiveFloatRangeValidator implements Validator {
+ private final float mMin;
+ private final float mMax;
+
+ public InclusiveFloatRangeValidator(float min, float max) {
+ mMin = min;
+ mMax = max;
+ }
+
+ public boolean validate(String value) {
+ try {
+ final float floatValue = Float.parseFloat(value);
+ return floatValue >= mMin && floatValue <= mMax;
+ } catch (NumberFormatException e) {
+ return false;
+ }
+ }
+ }
+
/**
* @deprecated Use {@link android.provider.Settings.Global#STAY_ON_WHILE_PLUGGED_IN} instead
*/
@@ -1741,6 +1846,9 @@ public final class Settings {
*/
public static final String END_BUTTON_BEHAVIOR = "end_button_behavior";
+ private static final Validator END_BUTTON_BEHAVIOR_VALIDATOR =
+ new InclusiveIntegerRangeValidator(0, 3);
+
/**
* END_BUTTON_BEHAVIOR value for "go home".
* @hide
@@ -1765,6 +1873,8 @@ public final class Settings {
*/
public static final String ADVANCED_SETTINGS = "advanced_settings";
+ private static final Validator ADVANCED_SETTINGS_VALIDATOR = sBooleanValidator;
+
/**
* ADVANCED_SETTINGS default value.
* @hide
@@ -1864,6 +1974,8 @@ public final class Settings {
@Deprecated
public static final String WIFI_USE_STATIC_IP = "wifi_use_static_ip";
+ private static final Validator WIFI_USE_STATIC_IP_VALIDATOR = sBooleanValidator;
+
/**
* The static IP address.
* <p>
@@ -1874,6 +1986,8 @@ public final class Settings {
@Deprecated
public static final String WIFI_STATIC_IP = "wifi_static_ip";
+ private static final Validator WIFI_STATIC_IP_VALIDATOR = sLenientIpAddressValidator;
+
/**
* If using static IP, the gateway's IP address.
* <p>
@@ -1884,6 +1998,8 @@ public final class Settings {
@Deprecated
public static final String WIFI_STATIC_GATEWAY = "wifi_static_gateway";
+ private static final Validator WIFI_STATIC_GATEWAY_VALIDATOR = sLenientIpAddressValidator;
+
/**
* If using static IP, the net mask.
* <p>
@@ -1894,6 +2010,8 @@ public final class Settings {
@Deprecated
public static final String WIFI_STATIC_NETMASK = "wifi_static_netmask";
+ private static final Validator WIFI_STATIC_NETMASK_VALIDATOR = sLenientIpAddressValidator;
+
/**
* If using static IP, the primary DNS's IP address.
* <p>
@@ -1904,6 +2022,8 @@ public final class Settings {
@Deprecated
public static final String WIFI_STATIC_DNS1 = "wifi_static_dns1";
+ private static final Validator WIFI_STATIC_DNS1_VALIDATOR = sLenientIpAddressValidator;
+
/**
* If using static IP, the secondary DNS's IP address.
* <p>
@@ -1914,6 +2034,7 @@ public final class Settings {
@Deprecated
public static final String WIFI_STATIC_DNS2 = "wifi_static_dns2";
+ private static final Validator WIFI_STATIC_DNS2_VALIDATOR = sLenientIpAddressValidator;
/**
* Determines whether remote devices may discover and/or connect to
@@ -1926,6 +2047,9 @@ public final class Settings {
public static final String BLUETOOTH_DISCOVERABILITY =
"bluetooth_discoverability";
+ private static final Validator BLUETOOTH_DISCOVERABILITY_VALIDATOR =
+ new InclusiveIntegerRangeValidator(0, 2);
+
/**
* Bluetooth discoverability timeout. If this value is nonzero, then
* Bluetooth becomes discoverable for a certain number of seconds,
@@ -1934,6 +2058,9 @@ public final class Settings {
public static final String BLUETOOTH_DISCOVERABILITY_TIMEOUT =
"bluetooth_discoverability_timeout";
+ private static final Validator BLUETOOTH_DISCOVERABILITY_TIMEOUT_VALIDATOR =
+ sNonNegativeIntegerValidator;
+
/**
* @deprecated Use {@link android.provider.Settings.Secure#LOCK_PATTERN_ENABLED}
* instead
@@ -1957,7 +2084,6 @@ public final class Settings {
public static final String LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED =
"lock_pattern_tactile_feedback_enabled";
-
/**
* A formatted string of the next alarm that is set, or the empty string
* if there is no alarm set.
@@ -1967,11 +2093,31 @@ public final class Settings {
@Deprecated
public static final String NEXT_ALARM_FORMATTED = "next_alarm_formatted";
+ private static final Validator NEXT_ALARM_FORMATTED_VALIDATOR = new Validator() {
+ private static final int MAX_LENGTH = 1000;
+ @Override
+ public boolean validate(String value) {
+ // TODO: No idea what the correct format is.
+ return value == null || value.length() < MAX_LENGTH;
+ }
+ };
+
/**
* Scaling factor for fonts, float.
*/
public static final String FONT_SCALE = "font_scale";
+ private static final Validator FONT_SCALE_VALIDATOR = new Validator() {
+ @Override
+ public boolean validate(String value) {
+ try {
+ return Float.parseFloat(value) >= 0;
+ } catch (NumberFormatException e) {
+ return false;
+ }
+ }
+ };
+
/**
* Name of an application package to be debugged.
*
@@ -1996,6 +2142,8 @@ public final class Settings {
@Deprecated
public static final String DIM_SCREEN = "dim_screen";
+ private static final Validator DIM_SCREEN_VALIDATOR = sBooleanValidator;
+
/**
* The amount of time in milliseconds before the device goes to sleep or begins
* to dream after a period of inactivity. This value is also known as the
@@ -2004,16 +2152,23 @@ public final class Settings {
*/
public static final String SCREEN_OFF_TIMEOUT = "screen_off_timeout";
+ private static final Validator SCREEN_OFF_TIMEOUT_VALIDATOR = sNonNegativeIntegerValidator;
+
/**
* The screen backlight brightness between 0 and 255.
*/
public static final String SCREEN_BRIGHTNESS = "screen_brightness";
+ private static final Validator SCREEN_BRIGHTNESS_VALIDATOR =
+ new InclusiveIntegerRangeValidator(0, 255);
+
/**
* Control whether to enable automatic brightness mode.
*/
public static final String SCREEN_BRIGHTNESS_MODE = "screen_brightness_mode";
+ private static final Validator SCREEN_BRIGHTNESS_MODE_VALIDATOR = sBooleanValidator;
+
/**
* Adjustment to auto-brightness to make it generally more (>0.0 <1.0)
* or less (<0.0 >-1.0) bright.
@@ -2021,6 +2176,9 @@ public final class Settings {
*/
public static final String SCREEN_AUTO_BRIGHTNESS_ADJ = "screen_auto_brightness_adj";
+ private static final Validator SCREEN_AUTO_BRIGHTNESS_ADJ_VALIDATOR =
+ new InclusiveFloatRangeValidator(-1, 1);
+
/**
* SCREEN_BRIGHTNESS_MODE value for manual mode.
*/
@@ -2056,12 +2214,18 @@ public final class Settings {
*/
public static final String MODE_RINGER_STREAMS_AFFECTED = "mode_ringer_streams_affected";
- /**
+ private static final Validator MODE_RINGER_STREAMS_AFFECTED_VALIDATOR =
+ sNonNegativeIntegerValidator;
+
+ /**
* Determines which streams are affected by mute. The
* stream type's bit should be set to 1 if it should be muted when a mute request
* is received.
*/
- public static final String MUTE_STREAMS_AFFECTED = "mute_streams_affected";
+ public static final String MUTE_STREAMS_AFFECTED = "mute_streams_affected";
+
+ private static final Validator MUTE_STREAMS_AFFECTED_VALIDATOR =
+ sNonNegativeIntegerValidator;
/**
* Whether vibrate is on for different events. This is used internally,
@@ -2069,6 +2233,8 @@ public final class Settings {
*/
public static final String VIBRATE_ON = "vibrate_on";
+ private static final Validator VIBRATE_ON_VALIDATOR = sBooleanValidator;
+
/**
* If 1, redirects the system vibrator to all currently attached input devices
* that support vibration. If there are no such input devices, then the system
@@ -2083,54 +2249,72 @@ public final class Settings {
*/
public static final String VIBRATE_INPUT_DEVICES = "vibrate_input_devices";
+ private static final Validator VIBRATE_INPUT_DEVICES_VALIDATOR = sBooleanValidator;
+
/**
* Ringer volume. This is used internally, changing this value will not
* change the volume. See AudioManager.
*/
public static final String VOLUME_RING = "volume_ring";
+ private static final Validator VOLUME_RING_VALIDATOR = sVolumeValidator;
+
/**
* System/notifications volume. This is used internally, changing this
* value will not change the volume. See AudioManager.
*/
public static final String VOLUME_SYSTEM = "volume_system";
+ private static final Validator VOLUME_SYSTEM_VALIDATOR = sVolumeValidator;
+
/**
* Voice call volume. This is used internally, changing this value will
* not change the volume. See AudioManager.
*/
public static final String VOLUME_VOICE = "volume_voice";
+ private static final Validator VOLUME_VOICE_VALIDATOR = sVolumeValidator;
+
/**
* Music/media/gaming volume. This is used internally, changing this
* value will not change the volume. See AudioManager.
*/
public static final String VOLUME_MUSIC = "volume_music";
+ private static final Validator VOLUME_MUSIC_VALIDATOR = sVolumeValidator;
+
/**
* Alarm volume. This is used internally, changing this
* value will not change the volume. See AudioManager.
*/
public static final String VOLUME_ALARM = "volume_alarm";
+ private static final Validator VOLUME_ALARM_VALIDATOR = sVolumeValidator;
+
/**
* Notification volume. This is used internally, changing this
* value will not change the volume. See AudioManager.
*/
public static final String VOLUME_NOTIFICATION = "volume_notification";
+ private static final Validator VOLUME_NOTIFICATION_VALIDATOR = sVolumeValidator;
+
/**
* Bluetooth Headset volume. This is used internally, changing this value will
* not change the volume. See AudioManager.
*/
public static final String VOLUME_BLUETOOTH_SCO = "volume_bluetooth_sco";
+ private static final Validator VOLUME_BLUETOOTH_SCO_VALIDATOR = sVolumeValidator;
+
/**
* Master volume (float in the range 0.0f to 1.0f).
* @hide
*/
public static final String VOLUME_MASTER = "volume_master";
+ private static final Validator VOLUME_MASTER_VALIDATOR = sVolumeValidator;
+
/**
* Master volume mute (int 1 = mute, 0 = not muted).
*
@@ -2138,6 +2322,8 @@ public final class Settings {
*/
public static final String VOLUME_MASTER_MUTE = "volume_master_mute";
+ private static final Validator VOLUME_MASTER_MUTE_VALIDATOR = sBooleanValidator;
+
/**
* Microphone mute (int 1 = mute, 0 = not muted).
*
@@ -2145,6 +2331,8 @@ public final class Settings {
*/
public static final String MICROPHONE_MUTE = "microphone_mute";
+ private static final Validator MICROPHONE_MUTE_VALIDATOR = sBooleanValidator;
+
/**
* Whether the notifications should use the ring volume (value of 1) or
* a separate notification volume (value of 0). In most cases, users
@@ -2163,6 +2351,8 @@ public final class Settings {
public static final String NOTIFICATIONS_USE_RING_VOLUME =
"notifications_use_ring_volume";
+ private static final Validator NOTIFICATIONS_USE_RING_VOLUME_VALIDATOR = sBooleanValidator;
+
/**
* Whether silent mode should allow vibration feedback. This is used
* internally in AudioService and the Sound settings activity to
@@ -2177,6 +2367,8 @@ public final class Settings {
*/
public static final String VIBRATE_IN_SILENT = "vibrate_in_silent";
+ private static final Validator VIBRATE_IN_SILENT_VALIDATOR = sBooleanValidator;
+
/**
* The mapping of stream type (integer) to its setting.
*/
@@ -2203,6 +2395,8 @@ public final class Settings {
*/
public static final String RINGTONE = "ringtone";
+ private static final Validator RINGTONE_VALIDATOR = sUriValidator;
+
/**
* A {@link Uri} that will point to the current default ringtone at any
* given time.
@@ -2221,6 +2415,8 @@ public final class Settings {
*/
public static final String NOTIFICATION_SOUND = "notification_sound";
+ private static final Validator NOTIFICATION_SOUND_VALIDATOR = sUriValidator;
+
/**
* A {@link Uri} that will point to the current default notification
* sound at any given time.
@@ -2237,6 +2433,8 @@ public final class Settings {
*/
public static final String ALARM_ALERT = "alarm_alert";
+ private static final Validator ALARM_ALERT_VALIDATOR = sUriValidator;
+
/**
* A {@link Uri} that will point to the current default alarm alert at
* any given time.
@@ -2252,30 +2450,52 @@ public final class Settings {
*/
public static final String MEDIA_BUTTON_RECEIVER = "media_button_receiver";
+ private static final Validator MEDIA_BUTTON_RECEIVER_VALIDATOR = new Validator() {
+ @Override
+ public boolean validate(String value) {
+ try {
+ ComponentName.unflattenFromString(value);
+ return true;
+ } catch (NullPointerException e) {
+ return false;
+ }
+ }
+ };
+
/**
* Setting to enable Auto Replace (AutoText) in text editors. 1 = On, 0 = Off
*/
public static final String TEXT_AUTO_REPLACE = "auto_replace";
+ private static final Validator TEXT_AUTO_REPLACE_VALIDATOR = sBooleanValidator;
+
/**
* Setting to enable Auto Caps in text editors. 1 = On, 0 = Off
*/
public static final String TEXT_AUTO_CAPS = "auto_caps";
+ private static final Validator TEXT_AUTO_CAPS_VALIDATOR = sBooleanValidator;
+
/**
* Setting to enable Auto Punctuate in text editors. 1 = On, 0 = Off. This
* feature converts two spaces to a "." and space.
*/
public static final String TEXT_AUTO_PUNCTUATE = "auto_punctuate";
+ private static final Validator TEXT_AUTO_PUNCTUATE_VALIDATOR = sBooleanValidator;
+
/**
* Setting to showing password characters in text editors. 1 = On, 0 = Off
*/
public static final String TEXT_SHOW_PASSWORD = "show_password";
+ private static final Validator TEXT_SHOW_PASSWORD_VALIDATOR = sBooleanValidator;
+
public static final String SHOW_GTALK_SERVICE_STATUS =
"SHOW_GTALK_SERVICE_STATUS";
+ private static final Validator SHOW_GTALK_SERVICE_STATUS_VALIDATOR = sBooleanValidator;
+
/**
* Name of activity to use for wallpaper on the home screen.
*
@@ -2284,6 +2504,18 @@ public final class Settings {
@Deprecated
public static final String WALLPAPER_ACTIVITY = "wallpaper_activity";
+ private static final Validator WALLPAPER_ACTIVITY_VALIDATOR = new Validator() {
+ private static final int MAX_LENGTH = 1000;
+
+ @Override
+ public boolean validate(String value) {
+ if (value != null && value.length() > MAX_LENGTH) {
+ return false;
+ }
+ return ComponentName.unflattenFromString(value) != null;
+ }
+ };
+
/**
* @deprecated Use {@link android.provider.Settings.Global#AUTO_TIME}
* instead
@@ -2305,6 +2537,10 @@ public final class Settings {
*/
public static final String TIME_12_24 = "time_12_24";
+ /** @hide */
+ public static final Validator TIME_12_24_VALIDATOR =
+ new DiscreteValueValidator(new String[] {"12", "24"});
+
/**
* Date format string
* mm/dd/yyyy
@@ -2313,6 +2549,19 @@ public final class Settings {
*/
public static final String DATE_FORMAT = "date_format";
+ /** @hide */
+ public static final Validator DATE_FORMAT_VALIDATOR = new Validator() {
+ @Override
+ public boolean validate(String value) {
+ try {
+ new SimpleDateFormat(value);
+ return true;
+ } catch (IllegalArgumentException e) {
+ return false;
+ }
+ }
+ };
+
/**
* Whether the setup wizard has been run before (on first boot), or if
* it still needs to be run.
@@ -2322,6 +2571,9 @@ public final class Settings {
*/
public static final String SETUP_WIZARD_HAS_RUN = "setup_wizard_has_run";
+ /** @hide */
+ public static final Validator SETUP_WIZARD_HAS_RUN_VALIDATOR = sBooleanValidator;
+
/**
* Scaling factor for normal window animations. Setting to 0 will disable window
* animations.
@@ -2358,6 +2610,9 @@ public final class Settings {
*/
public static final String ACCELEROMETER_ROTATION = "accelerometer_rotation";
+ /** @hide */
+ public static final Validator ACCELEROMETER_ROTATION_VALIDATOR = sBooleanValidator;
+
/**
* Default screen rotation when no other policy applies.
* When {@link #ACCELEROMETER_ROTATION} is zero and no on-screen Activity expresses a
@@ -2368,6 +2623,10 @@ public final class Settings {
*/
public static final String USER_ROTATION = "user_rotation";
+ /** @hide */
+ public static final Validator USER_ROTATION_VALIDATOR =
+ new InclusiveIntegerRangeValidator(0, 3);
+
/**
* Control whether the rotation lock toggle in the System UI should be hidden.
* Typically this is done for accessibility purposes to make it harder for
@@ -2382,6 +2641,10 @@ public final class Settings {
public static final String HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY =
"hide_rotation_lock_toggle_for_accessibility";
+ /** @hide */
+ public static final Validator HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY_VALIDATOR =
+ sBooleanValidator;
+
/**
* Whether the phone vibrates when it is ringing due to an incoming call. This will
* be used by Phone and Setting apps; it shouldn't affect other apps.
@@ -2396,12 +2659,18 @@ public final class Settings {
*/
public static final String VIBRATE_WHEN_RINGING = "vibrate_when_ringing";
+ /** @hide */
+ public static final Validator VIBRATE_WHEN_RINGING_VALIDATOR = sBooleanValidator;
+
/**
* Whether the audible DTMF tones are played by the dialer when dialing. The value is
* boolean (1 or 0).
*/
public static final String DTMF_TONE_WHEN_DIALING = "dtmf_tone";
+ /** @hide */
+ public static final Validator DTMF_TONE_WHEN_DIALING_VALIDATOR = sBooleanValidator;
+
/**
* CDMA only settings
* DTMF tone type played by the dialer when dialing.
@@ -2411,6 +2680,9 @@ public final class Settings {
*/
public static final String DTMF_TONE_TYPE_WHEN_DIALING = "dtmf_tone_type";
+ /** @hide */
+ public static final Validator DTMF_TONE_TYPE_WHEN_DIALING_VALIDATOR = sBooleanValidator;
+
/**
* Whether the hearing aid is enabled. The value is
* boolean (1 or 0).
@@ -2418,6 +2690,9 @@ public final class Settings {
*/
public static final String HEARING_AID = "hearing_aid";
+ /** @hide */
+ public static final Validator HEARING_AID_VALIDATOR = sBooleanValidator;
+
/**
* CDMA only settings
* TTY Mode
@@ -2429,18 +2704,27 @@ public final class Settings {
*/
public static final String TTY_MODE = "tty_mode";
+ /** @hide */
+ public static final Validator TTY_MODE_VALIDATOR = new InclusiveIntegerRangeValidator(0, 3);
+
/**
* Whether the sounds effects (key clicks, lid open ...) are enabled. The value is
* boolean (1 or 0).
*/
public static final String SOUND_EFFECTS_ENABLED = "sound_effects_enabled";
+ /** @hide */
+ public static final Validator SOUND_EFFECTS_ENABLED_VALIDATOR = sBooleanValidator;
+
/**
* Whether the haptic feedback (long presses, ...) are enabled. The value is
* boolean (1 or 0).
*/
public static final String HAPTIC_FEEDBACK_ENABLED = "haptic_feedback_enabled";
+ /** @hide */
+ public static final Validator HAPTIC_FEEDBACK_ENABLED_VALIDATOR = sBooleanValidator;
+
/**
* @deprecated Each application that shows web suggestions should have its own
* setting for this.
@@ -2448,6 +2732,9 @@ public final class Settings {
@Deprecated
public static final String SHOW_WEB_SUGGESTIONS = "show_web_suggestions";
+ /** @hide */
+ public static final Validator SHOW_WEB_SUGGESTIONS_VALIDATOR = sBooleanValidator;
+
/**
* Whether the notification LED should repeatedly flash when a notification is
* pending. The value is boolean (1 or 0).
@@ -2455,6 +2742,9 @@ public final class Settings {
*/
public static final String NOTIFICATION_LIGHT_PULSE = "notification_light_pulse";
+ /** @hide */
+ public static final Validator NOTIFICATION_LIGHT_PULSE_VALIDATOR = sBooleanValidator;
+
/**
* Show pointer location on screen?
* 0 = no
@@ -2463,6 +2753,9 @@ public final class Settings {
*/
public static final String POINTER_LOCATION = "pointer_location";
+ /** @hide */
+ public static final Validator POINTER_LOCATION_VALIDATOR = sBooleanValidator;
+
/**
* Show touch positions on screen?
* 0 = no
@@ -2471,6 +2764,9 @@ public final class Settings {
*/
public static final String SHOW_TOUCHES = "show_touches";
+ /** @hide */
+ public static final Validator SHOW_TOUCHES_VALIDATOR = sBooleanValidator;
+
/**
* Log raw orientation data from
* {@link com.android.server.policy.WindowOrientationListener} for use with the
@@ -2482,6 +2778,9 @@ public final class Settings {
public static final String WINDOW_ORIENTATION_LISTENER_LOG =
"window_orientation_listener_log";
+ /** @hide */
+ public static final Validator WINDOW_ORIENTATION_LISTENER_LOG_VALIDATOR = sBooleanValidator;
+
/**
* @deprecated Use {@link android.provider.Settings.Global#POWER_SOUNDS_ENABLED}
* instead
@@ -2504,12 +2803,18 @@ public final class Settings {
*/
public static final String LOCKSCREEN_SOUNDS_ENABLED = "lockscreen_sounds_enabled";
+ /** @hide */
+ public static final Validator LOCKSCREEN_SOUNDS_ENABLED_VALIDATOR = sBooleanValidator;
+
/**
* Whether the lockscreen should be completely disabled.
* @hide
*/
public static final String LOCKSCREEN_DISABLED = "lockscreen.disabled";
+ /** @hide */
+ public static final Validator LOCKSCREEN_DISABLED_VALIDATOR = sBooleanValidator;
+
/**
* @deprecated Use {@link android.provider.Settings.Global#LOW_BATTERY_SOUND}
* instead
@@ -2574,6 +2879,9 @@ public final class Settings {
*/
public static final String SIP_RECEIVE_CALLS = "sip_receive_calls";
+ /** @hide */
+ public static final Validator SIP_RECEIVE_CALLS_VALIDATOR = sBooleanValidator;
+
/**
* Call Preference String.
* "SIP_ALWAYS" : Always use SIP with network access
@@ -2582,18 +2890,28 @@ public final class Settings {
*/
public static final String SIP_CALL_OPTIONS = "sip_call_options";
+ /** @hide */
+ public static final Validator SIP_CALL_OPTIONS_VALIDATOR = new DiscreteValueValidator(
+ new String[] {"SIP_ALWAYS", "SIP_ADDRESS_ONLY"});
+
/**
* One of the sip call options: Always use SIP with network access.
* @hide
*/
public static final String SIP_ALWAYS = "SIP_ALWAYS";
+ /** @hide */
+ public static final Validator SIP_ALWAYS_VALIDATOR = sBooleanValidator;
+
/**
* One of the sip call options: Only if destination is a SIP address.
* @hide
*/
public static final String SIP_ADDRESS_ONLY = "SIP_ADDRESS_ONLY";
+ /** @hide */
+ public static final Validator SIP_ADDRESS_ONLY_VALIDATOR = sBooleanValidator;
+
/**
* @deprecated Use SIP_ALWAYS or SIP_ADDRESS_ONLY instead. Formerly used to indicate that
* the user should be prompted each time a call is made whether it should be placed using
@@ -2604,6 +2922,9 @@ public final class Settings {
@Deprecated
public static final String SIP_ASK_ME_EACH_TIME = "SIP_ASK_ME_EACH_TIME";
+ /** @hide */
+ public static final Validator SIP_ASK_ME_EACH_TIME_VALIDATOR = sBooleanValidator;
+
/**
* Pointer speed setting.
* This is an integer value in a range between -7 and +7, so there are 15 possible values.
@@ -2614,12 +2935,19 @@ public final class Settings {
*/
public static final String POINTER_SPEED = "pointer_speed";
+ /** @hide */
+ public static final Validator POINTER_SPEED_VALIDATOR =
+ new InclusiveFloatRangeValidator(-7, 7);
+
/**
* Whether lock-to-app will be triggered by long-press on recents.
* @hide
*/
public static final String LOCK_TO_APP_ENABLED = "lock_to_app_enabled";
+ /** @hide */
+ public static final Validator LOCK_TO_APP_ENABLED_VALIDATOR = sBooleanValidator;
+
/**
* I am the lolrus.
* <p>
@@ -2629,6 +2957,16 @@ public final class Settings {
*/
public static final String EGG_MODE = "egg_mode";
+ /** @hide */
+ public static final Validator EGG_MODE_VALIDATOR = sBooleanValidator;
+
+ /**
+ * IMPORTANT: If you add a new public settings you also have to add it to
+ * PUBLIC_SETTINGS below. If the new setting is hidden you have to add
+ * it to PRIVATE_SETTINGS below. Also add a validator that can validate
+ * the setting value. See an example above.
+ */
+
/**
* Settings to backup. This is here so that it's in the same place as the settings
* keys and easy to update.
@@ -2699,17 +3037,207 @@ public final class Settings {
};
/**
+ * These are all pulbic system settings
+ *
+ * @hide
+ */
+ public static final Set<String> PUBLIC_SETTINGS = new ArraySet<>();
+ static {
+ PUBLIC_SETTINGS.add(END_BUTTON_BEHAVIOR);
+ PUBLIC_SETTINGS.add(WIFI_USE_STATIC_IP);
+ PUBLIC_SETTINGS.add(WIFI_STATIC_IP);
+ PUBLIC_SETTINGS.add(WIFI_STATIC_GATEWAY);
+ PUBLIC_SETTINGS.add(WIFI_STATIC_NETMASK);
+ PUBLIC_SETTINGS.add(WIFI_STATIC_DNS1);
+ PUBLIC_SETTINGS.add(WIFI_STATIC_DNS2);
+ PUBLIC_SETTINGS.add(BLUETOOTH_DISCOVERABILITY);
+ PUBLIC_SETTINGS.add(BLUETOOTH_DISCOVERABILITY_TIMEOUT);
+ PUBLIC_SETTINGS.add(NEXT_ALARM_FORMATTED);
+ PUBLIC_SETTINGS.add(FONT_SCALE);
+ PUBLIC_SETTINGS.add(DIM_SCREEN);
+ PUBLIC_SETTINGS.add(SCREEN_OFF_TIMEOUT);
+ PUBLIC_SETTINGS.add(SCREEN_BRIGHTNESS);
+ PUBLIC_SETTINGS.add(SCREEN_BRIGHTNESS_MODE);
+ PUBLIC_SETTINGS.add(MODE_RINGER_STREAMS_AFFECTED);
+ PUBLIC_SETTINGS.add(MUTE_STREAMS_AFFECTED);
+ PUBLIC_SETTINGS.add(VIBRATE_ON);
+ PUBLIC_SETTINGS.add(VOLUME_RING);
+ PUBLIC_SETTINGS.add(VOLUME_SYSTEM);
+ PUBLIC_SETTINGS.add(VOLUME_VOICE);
+ PUBLIC_SETTINGS.add(VOLUME_MUSIC);
+ PUBLIC_SETTINGS.add(VOLUME_ALARM);
+ PUBLIC_SETTINGS.add(VOLUME_NOTIFICATION);
+ PUBLIC_SETTINGS.add(VOLUME_BLUETOOTH_SCO);
+ PUBLIC_SETTINGS.add(RINGTONE);
+ PUBLIC_SETTINGS.add(NOTIFICATION_SOUND);
+ PUBLIC_SETTINGS.add(ALARM_ALERT);
+ PUBLIC_SETTINGS.add(TEXT_AUTO_REPLACE);
+ PUBLIC_SETTINGS.add(TEXT_AUTO_CAPS);
+ PUBLIC_SETTINGS.add(TEXT_AUTO_PUNCTUATE);
+ PUBLIC_SETTINGS.add(TEXT_SHOW_PASSWORD);
+ PUBLIC_SETTINGS.add(SHOW_GTALK_SERVICE_STATUS);
+ PUBLIC_SETTINGS.add(WALLPAPER_ACTIVITY);
+ PUBLIC_SETTINGS.add(TIME_12_24);
+ PUBLIC_SETTINGS.add(DATE_FORMAT);
+ PUBLIC_SETTINGS.add(SETUP_WIZARD_HAS_RUN);
+ PUBLIC_SETTINGS.add(ACCELEROMETER_ROTATION);
+ PUBLIC_SETTINGS.add(USER_ROTATION);
+ PUBLIC_SETTINGS.add(DTMF_TONE_WHEN_DIALING);
+ PUBLIC_SETTINGS.add(SOUND_EFFECTS_ENABLED);
+ PUBLIC_SETTINGS.add(HAPTIC_FEEDBACK_ENABLED);
+ PUBLIC_SETTINGS.add(SHOW_WEB_SUGGESTIONS);
+ }
+
+ /**
+ * These are all hidden system settings.
+ *
+ * @hide
+ */
+ public static final Set<String> PRIVATE_SETTINGS = new ArraySet<>();
+ static {
+ PRIVATE_SETTINGS.add(WIFI_USE_STATIC_IP);
+ PRIVATE_SETTINGS.add(END_BUTTON_BEHAVIOR);
+ PRIVATE_SETTINGS.add(ADVANCED_SETTINGS);
+ PRIVATE_SETTINGS.add(SCREEN_AUTO_BRIGHTNESS_ADJ);
+ PRIVATE_SETTINGS.add(VIBRATE_INPUT_DEVICES);
+ PRIVATE_SETTINGS.add(VOLUME_MASTER);
+ PRIVATE_SETTINGS.add(VOLUME_MASTER_MUTE);
+ PRIVATE_SETTINGS.add(MICROPHONE_MUTE);
+ PRIVATE_SETTINGS.add(NOTIFICATIONS_USE_RING_VOLUME);
+ PRIVATE_SETTINGS.add(VIBRATE_IN_SILENT);
+ PRIVATE_SETTINGS.add(MEDIA_BUTTON_RECEIVER);
+ PRIVATE_SETTINGS.add(HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY);
+ PRIVATE_SETTINGS.add(VIBRATE_WHEN_RINGING);
+ PRIVATE_SETTINGS.add(DTMF_TONE_TYPE_WHEN_DIALING);
+ PRIVATE_SETTINGS.add(HEARING_AID);
+ PRIVATE_SETTINGS.add(TTY_MODE);
+ PRIVATE_SETTINGS.add(NOTIFICATION_LIGHT_PULSE);
+ PRIVATE_SETTINGS.add(POINTER_LOCATION);
+ PRIVATE_SETTINGS.add(SHOW_TOUCHES);
+ PRIVATE_SETTINGS.add(WINDOW_ORIENTATION_LISTENER_LOG);
+ PRIVATE_SETTINGS.add(POWER_SOUNDS_ENABLED);
+ PRIVATE_SETTINGS.add(DOCK_SOUNDS_ENABLED);
+ PRIVATE_SETTINGS.add(LOCKSCREEN_SOUNDS_ENABLED);
+ PRIVATE_SETTINGS.add(LOCKSCREEN_DISABLED);
+ PRIVATE_SETTINGS.add(LOW_BATTERY_SOUND);
+ PRIVATE_SETTINGS.add(DESK_DOCK_SOUND);
+ PRIVATE_SETTINGS.add(DESK_UNDOCK_SOUND);
+ PRIVATE_SETTINGS.add(CAR_DOCK_SOUND);
+ PRIVATE_SETTINGS.add(CAR_UNDOCK_SOUND);
+ PRIVATE_SETTINGS.add(LOCK_SOUND);
+ PRIVATE_SETTINGS.add(UNLOCK_SOUND);
+ PRIVATE_SETTINGS.add(SIP_RECEIVE_CALLS);
+ PRIVATE_SETTINGS.add(SIP_CALL_OPTIONS);
+ PRIVATE_SETTINGS.add(SIP_ALWAYS);
+ PRIVATE_SETTINGS.add(SIP_ADDRESS_ONLY);
+ PRIVATE_SETTINGS.add(SIP_ASK_ME_EACH_TIME);
+ PRIVATE_SETTINGS.add(POINTER_SPEED);
+ PRIVATE_SETTINGS.add(LOCK_TO_APP_ENABLED);
+ PRIVATE_SETTINGS.add(EGG_MODE);
+ }
+
+ /**
+ * These are all pulbic system settings
+ *
+ * @hide
+ */
+ public static final Map<String, Validator> VALIDATORS = new ArrayMap<>();
+ static {
+ VALIDATORS.put(END_BUTTON_BEHAVIOR,END_BUTTON_BEHAVIOR_VALIDATOR);
+ VALIDATORS.put(WIFI_USE_STATIC_IP, WIFI_USE_STATIC_IP_VALIDATOR);
+ VALIDATORS.put(BLUETOOTH_DISCOVERABILITY, BLUETOOTH_DISCOVERABILITY_VALIDATOR);
+ VALIDATORS.put(BLUETOOTH_DISCOVERABILITY_TIMEOUT,
+ BLUETOOTH_DISCOVERABILITY_TIMEOUT_VALIDATOR);
+ VALIDATORS.put(NEXT_ALARM_FORMATTED, NEXT_ALARM_FORMATTED_VALIDATOR);
+ VALIDATORS.put(FONT_SCALE, FONT_SCALE_VALIDATOR);
+ VALIDATORS.put(DIM_SCREEN, DIM_SCREEN_VALIDATOR);
+ VALIDATORS.put(SCREEN_OFF_TIMEOUT, SCREEN_OFF_TIMEOUT_VALIDATOR);
+ VALIDATORS.put(SCREEN_BRIGHTNESS, SCREEN_BRIGHTNESS_VALIDATOR);
+ VALIDATORS.put(SCREEN_BRIGHTNESS_MODE, SCREEN_BRIGHTNESS_MODE_VALIDATOR);
+ VALIDATORS.put(MODE_RINGER_STREAMS_AFFECTED, MODE_RINGER_STREAMS_AFFECTED_VALIDATOR);
+ VALIDATORS.put(MUTE_STREAMS_AFFECTED, MUTE_STREAMS_AFFECTED_VALIDATOR);
+ VALIDATORS.put(VIBRATE_ON, VIBRATE_ON_VALIDATOR);
+ VALIDATORS.put(VOLUME_RING, VOLUME_RING_VALIDATOR);
+ VALIDATORS.put(VOLUME_SYSTEM, VOLUME_SYSTEM_VALIDATOR);
+ VALIDATORS.put(VOLUME_VOICE, VOLUME_VOICE_VALIDATOR);
+ VALIDATORS.put(VOLUME_MUSIC, VOLUME_MUSIC_VALIDATOR);
+ VALIDATORS.put(VOLUME_ALARM, VOLUME_ALARM_VALIDATOR);
+ VALIDATORS.put(VOLUME_NOTIFICATION, VOLUME_NOTIFICATION_VALIDATOR);
+ VALIDATORS.put(VOLUME_BLUETOOTH_SCO, VOLUME_BLUETOOTH_SCO_VALIDATOR);
+ VALIDATORS.put(RINGTONE, RINGTONE_VALIDATOR);
+ VALIDATORS.put(NOTIFICATION_SOUND, NOTIFICATION_SOUND_VALIDATOR);
+ VALIDATORS.put(ALARM_ALERT, ALARM_ALERT_VALIDATOR);
+ VALIDATORS.put(TEXT_AUTO_REPLACE, TEXT_AUTO_REPLACE_VALIDATOR);
+ VALIDATORS.put(TEXT_AUTO_CAPS, TEXT_AUTO_CAPS_VALIDATOR);
+ VALIDATORS.put(TEXT_AUTO_PUNCTUATE, TEXT_AUTO_PUNCTUATE_VALIDATOR);
+ VALIDATORS.put(TEXT_SHOW_PASSWORD, TEXT_SHOW_PASSWORD_VALIDATOR);
+ VALIDATORS.put(SHOW_GTALK_SERVICE_STATUS, SHOW_GTALK_SERVICE_STATUS_VALIDATOR);
+ VALIDATORS.put(WALLPAPER_ACTIVITY, WALLPAPER_ACTIVITY_VALIDATOR);
+ VALIDATORS.put(TIME_12_24, TIME_12_24_VALIDATOR);
+ VALIDATORS.put(DATE_FORMAT, DATE_FORMAT_VALIDATOR);
+ VALIDATORS.put(SETUP_WIZARD_HAS_RUN, SETUP_WIZARD_HAS_RUN_VALIDATOR);
+ VALIDATORS.put(ACCELEROMETER_ROTATION, ACCELEROMETER_ROTATION_VALIDATOR);
+ VALIDATORS.put(USER_ROTATION, USER_ROTATION_VALIDATOR);
+ VALIDATORS.put(DTMF_TONE_WHEN_DIALING, DTMF_TONE_WHEN_DIALING_VALIDATOR);
+ VALIDATORS.put(SOUND_EFFECTS_ENABLED, SOUND_EFFECTS_ENABLED_VALIDATOR);
+ VALIDATORS.put(HAPTIC_FEEDBACK_ENABLED, HAPTIC_FEEDBACK_ENABLED_VALIDATOR);
+ VALIDATORS.put(SHOW_WEB_SUGGESTIONS, SHOW_WEB_SUGGESTIONS_VALIDATOR);
+ VALIDATORS.put(WIFI_USE_STATIC_IP, WIFI_USE_STATIC_IP_VALIDATOR);
+ VALIDATORS.put(END_BUTTON_BEHAVIOR, END_BUTTON_BEHAVIOR_VALIDATOR);
+ VALIDATORS.put(ADVANCED_SETTINGS, ADVANCED_SETTINGS_VALIDATOR);
+ VALIDATORS.put(SCREEN_AUTO_BRIGHTNESS_ADJ, SCREEN_AUTO_BRIGHTNESS_ADJ_VALIDATOR);
+ VALIDATORS.put(VIBRATE_INPUT_DEVICES, VIBRATE_INPUT_DEVICES_VALIDATOR);
+ VALIDATORS.put(VOLUME_MASTER, VOLUME_MASTER_VALIDATOR);
+ VALIDATORS.put(VOLUME_MASTER_MUTE, VOLUME_MASTER_MUTE_VALIDATOR);
+ VALIDATORS.put(MICROPHONE_MUTE, MICROPHONE_MUTE_VALIDATOR);
+ VALIDATORS.put(NOTIFICATIONS_USE_RING_VOLUME, NOTIFICATIONS_USE_RING_VOLUME_VALIDATOR);
+ VALIDATORS.put(VIBRATE_IN_SILENT, VIBRATE_IN_SILENT_VALIDATOR);
+ VALIDATORS.put(MEDIA_BUTTON_RECEIVER, MEDIA_BUTTON_RECEIVER_VALIDATOR);
+ VALIDATORS.put(HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY,
+ HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY_VALIDATOR);
+ VALIDATORS.put(VIBRATE_WHEN_RINGING, VIBRATE_WHEN_RINGING_VALIDATOR);
+ VALIDATORS.put(DTMF_TONE_TYPE_WHEN_DIALING, DTMF_TONE_TYPE_WHEN_DIALING_VALIDATOR);
+ VALIDATORS.put(HEARING_AID, HEARING_AID_VALIDATOR);
+ VALIDATORS.put(TTY_MODE, TTY_MODE_VALIDATOR);
+ VALIDATORS.put(NOTIFICATION_LIGHT_PULSE, NOTIFICATION_LIGHT_PULSE_VALIDATOR);
+ VALIDATORS.put(POINTER_LOCATION, POINTER_LOCATION_VALIDATOR);
+ VALIDATORS.put(SHOW_TOUCHES, SHOW_TOUCHES_VALIDATOR);
+ VALIDATORS.put(WINDOW_ORIENTATION_LISTENER_LOG,
+ WINDOW_ORIENTATION_LISTENER_LOG_VALIDATOR);
+ VALIDATORS.put(LOCKSCREEN_SOUNDS_ENABLED, LOCKSCREEN_SOUNDS_ENABLED_VALIDATOR);
+ VALIDATORS.put(LOCKSCREEN_DISABLED, LOCKSCREEN_DISABLED_VALIDATOR);
+ VALIDATORS.put(SIP_RECEIVE_CALLS, SIP_RECEIVE_CALLS_VALIDATOR);
+ VALIDATORS.put(SIP_CALL_OPTIONS, SIP_CALL_OPTIONS_VALIDATOR);
+ VALIDATORS.put(SIP_ALWAYS, SIP_ALWAYS_VALIDATOR);
+ VALIDATORS.put(SIP_ADDRESS_ONLY, SIP_ADDRESS_ONLY_VALIDATOR);
+ VALIDATORS.put(SIP_ASK_ME_EACH_TIME, SIP_ASK_ME_EACH_TIME_VALIDATOR);
+ VALIDATORS.put(POINTER_SPEED, POINTER_SPEED_VALIDATOR);
+ VALIDATORS.put(LOCK_TO_APP_ENABLED, LOCK_TO_APP_ENABLED_VALIDATOR);
+ VALIDATORS.put(EGG_MODE, EGG_MODE_VALIDATOR);
+ VALIDATORS.put(WIFI_STATIC_IP, WIFI_STATIC_IP_VALIDATOR);
+ VALIDATORS.put(WIFI_STATIC_GATEWAY, WIFI_STATIC_GATEWAY_VALIDATOR);
+ VALIDATORS.put(WIFI_STATIC_NETMASK, WIFI_STATIC_NETMASK_VALIDATOR);
+ VALIDATORS.put(WIFI_STATIC_DNS1, WIFI_STATIC_DNS1_VALIDATOR);
+ VALIDATORS.put(WIFI_STATIC_DNS2, WIFI_STATIC_DNS2_VALIDATOR);
+ }
+
+ /**
* These entries are considered common between the personal and the managed profile,
* since the managed profile doesn't get to change them.
- * @hide
*/
- public static final String[] CLONE_TO_MANAGED_PROFILE = {
- DATE_FORMAT,
- HAPTIC_FEEDBACK_ENABLED,
- SOUND_EFFECTS_ENABLED,
- TEXT_SHOW_PASSWORD,
- TIME_12_24
- };
+ private static final Set<String> CLONE_TO_MANAGED_PROFILE = new ArraySet<>();
+ static {
+ CLONE_TO_MANAGED_PROFILE.add(DATE_FORMAT);
+ CLONE_TO_MANAGED_PROFILE.add(HAPTIC_FEEDBACK_ENABLED);
+ CLONE_TO_MANAGED_PROFILE.add(SOUND_EFFECTS_ENABLED);
+ CLONE_TO_MANAGED_PROFILE.add(TEXT_SHOW_PASSWORD);
+ CLONE_TO_MANAGED_PROFILE.add(TIME_12_24);
+ }
+
+ /** @hide */
+ public static void getCloneToManagedProfileSettings(Set<String> outKeySet) {
+ outKeySet.addAll(CLONE_TO_MANAGED_PROFILE);
+ }
/**
* When to use Wi-Fi calling
@@ -3099,7 +3627,7 @@ public final class Settings {
}
/** @hide */
- public static void getMovedKeys(HashSet<String> outKeySet) {
+ public static void getMovedToGlobalSettings(Set<String> outKeySet) {
outKeySet.addAll(MOVED_TO_GLOBAL);
}
@@ -4762,6 +5290,10 @@ public final class Settings {
public static final String BAR_SERVICE_COMPONENT = "bar_service_component";
/** @hide */
+ public static final String VOLUME_CONTROLLER_SERVICE_COMPONENT
+ = "volume_controller_service_component";
+
+ /** @hide */
public static final String IMMERSIVE_MODE_CONFIRMATIONS = "immersive_mode_confirmations";
/**
@@ -4896,22 +5428,27 @@ public final class Settings {
/**
* These entries are considered common between the personal and the managed profile,
* since the managed profile doesn't get to change them.
- * @hide
*/
- public static final String[] CLONE_TO_MANAGED_PROFILE = {
- ACCESSIBILITY_ENABLED,
- ALLOW_MOCK_LOCATION,
- ALLOWED_GEOLOCATION_ORIGINS,
- DEFAULT_INPUT_METHOD,
- ENABLED_ACCESSIBILITY_SERVICES,
- ENABLED_INPUT_METHODS,
- LOCATION_MODE,
- LOCATION_PROVIDERS_ALLOWED,
- LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS,
- SELECTED_INPUT_METHOD_SUBTYPE,
- SELECTED_SPELL_CHECKER,
- SELECTED_SPELL_CHECKER_SUBTYPE
- };
+ private static final Set<String> CLONE_TO_MANAGED_PROFILE = new ArraySet<>();
+ static {
+ CLONE_TO_MANAGED_PROFILE.add(ACCESSIBILITY_ENABLED);
+ CLONE_TO_MANAGED_PROFILE.add(ALLOW_MOCK_LOCATION);
+ CLONE_TO_MANAGED_PROFILE.add(ALLOWED_GEOLOCATION_ORIGINS);
+ CLONE_TO_MANAGED_PROFILE.add(DEFAULT_INPUT_METHOD);
+ CLONE_TO_MANAGED_PROFILE.add(ENABLED_ACCESSIBILITY_SERVICES);
+ CLONE_TO_MANAGED_PROFILE.add(ENABLED_INPUT_METHODS);
+ CLONE_TO_MANAGED_PROFILE.add(LOCATION_MODE);
+ CLONE_TO_MANAGED_PROFILE.add(LOCATION_PROVIDERS_ALLOWED);
+ CLONE_TO_MANAGED_PROFILE.add(LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS);
+ CLONE_TO_MANAGED_PROFILE.add(SELECTED_INPUT_METHOD_SUBTYPE);
+ CLONE_TO_MANAGED_PROFILE.add(SELECTED_SPELL_CHECKER);
+ CLONE_TO_MANAGED_PROFILE.add(SELECTED_SPELL_CHECKER_SUBTYPE);
+ }
+
+ /** @hide */
+ public static void getCloneToManagedProfileSettings(Set<String> outKeySet) {
+ outKeySet.addAll(CLONE_TO_MANAGED_PROFILE);
+ }
/**
* Helper method for determining if a location provider is enabled.
@@ -6693,6 +7230,11 @@ public final class Settings {
MOVED_TO_SECURE.add(Settings.Global.INSTALL_NON_MARKET_APPS);
}
+ /** @hide */
+ public static void getMovedToSecureSettings(Set<String> outKeySet) {
+ outKeySet.addAll(MOVED_TO_SECURE);
+ }
+
/**
* Look up a name in the database.
* @param resolver to access the database with
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index 3c57dda..fa5ac42 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -18,6 +18,7 @@ package android.service.dreams;
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import android.annotation.Nullable;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.app.AlarmManager;
@@ -442,6 +443,7 @@ public class DreamService extends Service implements Window.Callback {
*
* @return The view if found or null otherwise.
*/
+ @Nullable
public View findViewById(int id) {
return getWindow().findViewById(id);
}
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index 3d39b18..0860153 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -77,6 +77,14 @@ public abstract class NotificationListenerService extends Service {
*/
public static final int INTERRUPTION_FILTER_NONE = 3;
+ /** {@link #getCurrentInterruptionFilter() Interruption filter} constant - returned when
+ * the value is unavailable for any reason. For example, before the notification listener
+ * is connected.
+ *
+ * {@see #onListenerConnected()}
+ */
+ public static final int INTERRUPTION_FILTER_UNKNOWN = 0;
+
/** {@link #getCurrentListenerHints() Listener hints} constant - the primary device UI
* should disable notification sound, vibrating and other visual or aural effects.
* This does not change the interruption filter, only the effects. **/
@@ -473,15 +481,16 @@ public abstract class NotificationListenerService extends Service {
* <p>
* Listen for updates using {@link #onInterruptionFilterChanged(int)}.
*
- * @return One of the INTERRUPTION_FILTER_ constants, or 0 on errors.
+ * @return One of the INTERRUPTION_FILTER_ constants, or INTERRUPTION_FILTER_UNKNOWN when
+ * unavailable.
*/
public final int getCurrentInterruptionFilter() {
- if (!isBound()) return 0;
+ if (!isBound()) return INTERRUPTION_FILTER_UNKNOWN;
try {
return getNotificationInterface().getInterruptionFilterFromListener(mWrapper);
} catch (android.os.RemoteException ex) {
Log.v(TAG, "Unable to contact notification manager", ex);
- return 0;
+ return INTERRUPTION_FILTER_UNKNOWN;
}
}
diff --git a/core/java/android/text/SpannableStringBuilder.java b/core/java/android/text/SpannableStringBuilder.java
index 06df683..7ce44e1 100644
--- a/core/java/android/text/SpannableStringBuilder.java
+++ b/core/java/android/text/SpannableStringBuilder.java
@@ -26,6 +26,7 @@ import com.android.internal.util.GrowingArrayUtils;
import libcore.util.EmptyArray;
import java.lang.reflect.Array;
+import java.util.IdentityHashMap;
/**
* This is the class for text whose content and markup can both be changed.
@@ -68,6 +69,7 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
mSpanStarts = EmptyArray.INT;
mSpanEnds = EmptyArray.INT;
mSpanFlags = EmptyArray.INT;
+ mSpanMax = EmptyArray.INT;
if (text instanceof Spanned) {
Spanned sp = (Spanned) text;
@@ -94,6 +96,7 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
setSpan(false, spans[i], st, en, fl);
}
+ restoreInvariants();
}
}
@@ -147,9 +150,12 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
if (mGapLength < 1)
new Exception("mGapLength < 1").printStackTrace();
- for (int i = 0; i < mSpanCount; i++) {
- if (mSpanStarts[i] > mGapStart) mSpanStarts[i] += delta;
- if (mSpanEnds[i] > mGapStart) mSpanEnds[i] += delta;
+ if (mSpanCount != 0) {
+ for (int i = 0; i < mSpanCount; i++) {
+ if (mSpanStarts[i] > mGapStart) mSpanStarts[i] += delta;
+ if (mSpanEnds[i] > mGapStart) mSpanEnds[i] += delta;
+ }
+ calcMax(treeRoot());
}
}
@@ -167,35 +173,38 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
System.arraycopy(mText, where + mGapLength - overlap, mText, mGapStart, overlap);
}
- // XXX be more clever
- for (int i = 0; i < mSpanCount; i++) {
- int start = mSpanStarts[i];
- int end = mSpanEnds[i];
-
- if (start > mGapStart)
- start -= mGapLength;
- if (start > where)
- start += mGapLength;
- else if (start == where) {
- int flag = (mSpanFlags[i] & START_MASK) >> START_SHIFT;
+ // TODO: be more clever (although the win really isn't that big)
+ if (mSpanCount != 0) {
+ for (int i = 0; i < mSpanCount; i++) {
+ int start = mSpanStarts[i];
+ int end = mSpanEnds[i];
- if (flag == POINT || (atEnd && flag == PARAGRAPH))
+ if (start > mGapStart)
+ start -= mGapLength;
+ if (start > where)
start += mGapLength;
- }
+ else if (start == where) {
+ int flag = (mSpanFlags[i] & START_MASK) >> START_SHIFT;
- if (end > mGapStart)
- end -= mGapLength;
- if (end > where)
- end += mGapLength;
- else if (end == where) {
- int flag = (mSpanFlags[i] & END_MASK);
+ if (flag == POINT || (atEnd && flag == PARAGRAPH))
+ start += mGapLength;
+ }
- if (flag == POINT || (atEnd && flag == PARAGRAPH))
+ if (end > mGapStart)
+ end -= mGapLength;
+ if (end > where)
end += mGapLength;
- }
+ else if (end == where) {
+ int flag = (mSpanFlags[i] & END_MASK);
+
+ if (flag == POINT || (atEnd && flag == PARAGRAPH))
+ end += mGapLength;
+ }
- mSpanStarts[i] = start;
- mSpanEnds[i] = end;
+ mSpanStarts[i] = start;
+ mSpanEnds[i] = end;
+ }
+ calcMax(treeRoot());
}
mGapStart = where;
@@ -243,6 +252,9 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
sendSpanRemoved(what, ostart, oend);
}
+ if (mIndexOfSpan != null) {
+ mIndexOfSpan.clear();
+ }
}
// Documentation from interface
@@ -277,12 +289,39 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
return append(String.valueOf(text));
}
+ // Returns true if a node was removed (so we can restart search from root)
+ private boolean removeSpansForChange(int start, int end, boolean textIsRemoved, int i) {
+ if ((i & 1) != 0) {
+ // internal tree node
+ if (resolveGap(mSpanMax[i]) >= start &&
+ removeSpansForChange(start, end, textIsRemoved, leftChild(i))) {
+ return true;
+ }
+ }
+ if (i < mSpanCount) {
+ if ((mSpanFlags[i] & Spanned.SPAN_EXCLUSIVE_EXCLUSIVE) ==
+ Spanned.SPAN_EXCLUSIVE_EXCLUSIVE &&
+ mSpanStarts[i] >= start && mSpanStarts[i] < mGapStart + mGapLength &&
+ mSpanEnds[i] >= start && mSpanEnds[i] < mGapStart + mGapLength &&
+ // The following condition indicates that the span would become empty
+ (textIsRemoved || mSpanStarts[i] > start || mSpanEnds[i] < mGapStart)) {
+ mIndexOfSpan.remove(mSpans[i]);
+ removeSpan(i);
+ return true;
+ }
+ return resolveGap(mSpanStarts[i]) <= end && (i & 1) != 0 &&
+ removeSpansForChange(start, end, textIsRemoved, rightChild(i));
+ }
+ return false;
+ }
+
private void change(int start, int end, CharSequence cs, int csStart, int csEnd) {
// Can be negative
final int replacedLength = end - start;
final int replacementLength = csEnd - csStart;
final int nbNewChars = replacementLength - replacedLength;
+ boolean changed = false;
for (int i = mSpanCount - 1; i >= 0; i--) {
int spanStart = mSpanStarts[i];
if (spanStart > mGapStart)
@@ -309,8 +348,10 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
break;
}
- if (spanStart != ost || spanEnd != oen)
+ if (spanStart != ost || spanEnd != oen) {
setSpan(false, mSpans[i], spanStart, spanEnd, mSpanFlags[i]);
+ changed = true;
+ }
}
int flags = 0;
@@ -320,6 +361,9 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
else if (spanEnd == end + nbNewChars) flags |= SPAN_END_AT_END;
mSpanFlags[i] |= flags;
}
+ if (changed) {
+ restoreInvariants();
+ }
moveGapTo(end);
@@ -331,23 +375,10 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
// The removal pass needs to be done before the gap is updated in order to broadcast the
// correct previous positions to the correct intersecting SpanWatchers
if (replacedLength > 0) { // no need for span fixup on pure insertion
- // A for loop will not work because the array is being modified
- // Do not iterate in reverse to keep the SpanWatchers notified in ordering
- // Also, a removed SpanWatcher should not get notified of removed spans located
- // further in the span array.
- int i = 0;
- while (i < mSpanCount) {
- if ((mSpanFlags[i] & Spanned.SPAN_EXCLUSIVE_EXCLUSIVE) ==
- Spanned.SPAN_EXCLUSIVE_EXCLUSIVE &&
- mSpanStarts[i] >= start && mSpanStarts[i] < mGapStart + mGapLength &&
- mSpanEnds[i] >= start && mSpanEnds[i] < mGapStart + mGapLength &&
- // This condition indicates that the span would become empty
- (textIsRemoved || mSpanStarts[i] > start || mSpanEnds[i] < mGapStart)) {
- removeSpan(i);
- continue; // do not increment i, spans will be shifted left in the array
- }
-
- i++;
+ while (mSpanCount > 0 &&
+ removeSpansForChange(start, end, textIsRemoved, treeRoot())) {
+ // keep deleting spans as needed, and restart from root after every deletion
+ // because deletion can invalidate an index.
}
}
@@ -360,6 +391,7 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
TextUtils.getChars(cs, csStart, csEnd, mText, start);
if (replacedLength > 0) { // no need for span fixup on pure insertion
+ // TODO potential optimization: only update bounds on intersecting spans
final boolean atEnd = (mGapStart + mGapLength == mText.length);
for (int i = 0; i < mSpanCount; i++) {
@@ -371,10 +403,10 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
mSpanEnds[i] = updatedIntervalBound(mSpanEnds[i], start, nbNewChars, endFlag,
atEnd, textIsRemoved);
}
+ // TODO potential optimization: only fix up invariants when bounds actually changed
+ restoreInvariants();
}
- mSpanCountBeforeAdd = mSpanCount;
-
if (cs instanceof Spanned) {
Spanned sp = (Spanned) cs;
Object[] spans = sp.getSpans(csStart, csEnd, Object.class);
@@ -389,9 +421,10 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
// Add span only if this object is not yet used as a span in this string
if (getSpanStart(spans[i]) < 0) {
setSpan(false, spans[i], st - csStart + start, en - csStart + start,
- sp.getSpanFlags(spans[i]));
+ sp.getSpanFlags(spans[i]) | SPAN_ADDED);
}
}
+ restoreInvariants();
}
}
@@ -427,6 +460,7 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
return offset;
}
+ // Note: caller is responsible for removing the mIndexOfSpan entry.
private void removeSpan(int i) {
Object object = mSpans[i];
@@ -444,8 +478,12 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
mSpanCount--;
+ invalidateIndex(i);
mSpans[mSpanCount] = null;
+ // Invariants must be restored before sending span removed notifications.
+ restoreInvariants();
+
sendSpanRemoved(object, start, end);
}
@@ -496,10 +534,12 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
change(start, end, tb, tbstart, tbend);
if (adjustSelection) {
+ boolean changed = false;
if (selectionStart > start && selectionStart < end) {
final int offset = (selectionStart - start) * newLen / origLen;
selectionStart = start + offset;
+ changed = true;
setSpan(false, Selection.SELECTION_START, selectionStart, selectionStart,
Spanned.SPAN_POINT_POINT);
}
@@ -507,9 +547,13 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
final int offset = (selectionEnd - start) * newLen / origLen;
selectionEnd = start + offset;
+ changed = true;
setSpan(false, Selection.SELECTION_END, selectionEnd, selectionEnd,
Spanned.SPAN_POINT_POINT);
}
+ if (changed) {
+ restoreInvariants();
+ }
}
sendTextChanged(textWatchers, start, origLen, newLen);
@@ -536,12 +580,15 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
}
private void sendToSpanWatchers(int replaceStart, int replaceEnd, int nbNewChars) {
- for (int i = 0; i < mSpanCountBeforeAdd; i++) {
+ for (int i = 0; i < mSpanCount; i++) {
+ int spanFlags = mSpanFlags[i];
+
+ // This loop handles only modified (not added) spans.
+ if ((spanFlags & SPAN_ADDED) != 0) continue;
int spanStart = mSpanStarts[i];
int spanEnd = mSpanEnds[i];
if (spanStart > mGapStart) spanStart -= mGapLength;
if (spanEnd > mGapStart) spanEnd -= mGapLength;
- int spanFlags = mSpanFlags[i];
int newReplaceEnd = replaceEnd + nbNewChars;
boolean spanChanged = false;
@@ -588,13 +635,17 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
mSpanFlags[i] &= ~SPAN_START_END_MASK;
}
- // The spans starting at mIntermediateSpanCount were added from the replacement text
- for (int i = mSpanCountBeforeAdd; i < mSpanCount; i++) {
- int spanStart = mSpanStarts[i];
- int spanEnd = mSpanEnds[i];
- if (spanStart > mGapStart) spanStart -= mGapLength;
- if (spanEnd > mGapStart) spanEnd -= mGapLength;
- sendSpanAdded(mSpans[i], spanStart, spanEnd);
+ // Handle added spans
+ for (int i = 0; i < mSpanCount; i++) {
+ int spanFlags = mSpanFlags[i];
+ if ((spanFlags & SPAN_ADDED) != 0) {
+ mSpanFlags[i] &= ~SPAN_ADDED;
+ int spanStart = mSpanStarts[i];
+ int spanEnd = mSpanEnds[i];
+ if (spanStart > mGapStart) spanStart -= mGapLength;
+ if (spanEnd > mGapStart) spanEnd -= mGapLength;
+ sendSpanAdded(mSpans[i], spanStart, spanEnd);
+ }
}
}
@@ -607,6 +658,9 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
setSpan(true, what, start, end, flags);
}
+ // Note: if send is false, then it is the caller's responsibility to restore
+ // invariants. If send is false and the span already exists, then this method
+ // will not change the index of any spans.
private void setSpan(boolean send, Object what, int start, int end, int flags) {
checkRange("setSpan", start, end);
@@ -661,8 +715,10 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
int count = mSpanCount;
Object[] spans = mSpans;
- for (int i = 0; i < count; i++) {
- if (spans[i] == what) {
+ if (mIndexOfSpan != null) {
+ Integer index = mIndexOfSpan.get(what);
+ if (index != null) {
+ int i = index;
int ostart = mSpanStarts[i];
int oend = mSpanEnds[i];
@@ -675,7 +731,10 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
mSpanEnds[i] = end;
mSpanFlags[i] = flags;
- if (send) sendSpanChanged(what, ostart, oend, nstart, nend);
+ if (send) {
+ restoreInvariants();
+ sendSpanChanged(what, ostart, oend, nstart, nend);
+ }
return;
}
@@ -685,43 +744,48 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
mSpanStarts = GrowingArrayUtils.append(mSpanStarts, mSpanCount, start);
mSpanEnds = GrowingArrayUtils.append(mSpanEnds, mSpanCount, end);
mSpanFlags = GrowingArrayUtils.append(mSpanFlags, mSpanCount, flags);
+ invalidateIndex(mSpanCount);
mSpanCount++;
+ // Make sure there is enough room for empty interior nodes.
+ // This magic formula computes the size of the smallest perfect binary
+ // tree no smaller than mSpanCount.
+ int sizeOfMax = 2 * treeRoot() + 1;
+ if (mSpanMax.length < sizeOfMax) {
+ mSpanMax = new int[sizeOfMax];
+ }
- if (send) sendSpanAdded(what, nstart, nend);
+ if (send) {
+ restoreInvariants();
+ sendSpanAdded(what, nstart, nend);
+ }
}
/**
* Remove the specified markup object from the buffer.
*/
public void removeSpan(Object what) {
- for (int i = mSpanCount - 1; i >= 0; i--) {
- if (mSpans[i] == what) {
- removeSpan(i);
- return;
- }
+ if (mIndexOfSpan == null) return;
+ Integer i = mIndexOfSpan.remove(what);
+ if (i != null) {
+ removeSpan(i.intValue());
}
}
/**
+ * Return externally visible offset given offset into gapped buffer.
+ */
+ private int resolveGap(int i) {
+ return i > mGapStart ? i - mGapLength : i;
+ }
+
+ /**
* Return the buffer offset of the beginning of the specified
* markup object, or -1 if it is not attached to this buffer.
*/
public int getSpanStart(Object what) {
- int count = mSpanCount;
- Object[] spans = mSpans;
-
- for (int i = count - 1; i >= 0; i--) {
- if (spans[i] == what) {
- int where = mSpanStarts[i];
-
- if (where > mGapStart)
- where -= mGapLength;
-
- return where;
- }
- }
-
- return -1;
+ if (mIndexOfSpan == null) return -1;
+ Integer i = mIndexOfSpan.get(what);
+ return i == null ? -1 : resolveGap(mSpanStarts[i]);
}
/**
@@ -729,21 +793,9 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
* markup object, or -1 if it is not attached to this buffer.
*/
public int getSpanEnd(Object what) {
- int count = mSpanCount;
- Object[] spans = mSpans;
-
- for (int i = count - 1; i >= 0; i--) {
- if (spans[i] == what) {
- int where = mSpanEnds[i];
-
- if (where > mGapStart)
- where -= mGapLength;
-
- return where;
- }
- }
-
- return -1;
+ if (mIndexOfSpan == null) return -1;
+ Integer i = mIndexOfSpan.get(what);
+ return i == null ? -1 : resolveGap(mSpanEnds[i]);
}
/**
@@ -751,16 +803,9 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
* markup object, or 0 if it is not attached to this buffer.
*/
public int getSpanFlags(Object what) {
- int count = mSpanCount;
- Object[] spans = mSpans;
-
- for (int i = count - 1; i >= 0; i--) {
- if (spans[i] == what) {
- return mSpanFlags[i];
- }
- }
-
- return 0;
+ if (mIndexOfSpan == null) return 0;
+ Integer i = mIndexOfSpan.get(what);
+ return i == null ? 0 : mSpanFlags[i];
}
/**
@@ -770,59 +815,84 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
*/
@SuppressWarnings("unchecked")
public <T> T[] getSpans(int queryStart, int queryEnd, Class<T> kind) {
- if (kind == null) return ArrayUtils.emptyArray(kind);
+ if (kind == null || mSpanCount == 0) return ArrayUtils.emptyArray(kind);
+ int count = countSpans(queryStart, queryEnd, kind, treeRoot());
+ if (count == 0) {
+ return ArrayUtils.emptyArray(kind);
+ }
- int spanCount = mSpanCount;
- Object[] spans = mSpans;
- int[] starts = mSpanStarts;
- int[] ends = mSpanEnds;
- int[] flags = mSpanFlags;
- int gapstart = mGapStart;
- int gaplen = mGapLength;
+ // Safe conversion, but requires a suppressWarning
+ T[] ret = (T[]) Array.newInstance(kind, count);
+ getSpansRec(queryStart, queryEnd, kind, treeRoot(), ret, 0);
+ return ret;
+ }
+ private int countSpans(int queryStart, int queryEnd, Class kind, int i) {
int count = 0;
- T[] ret = null;
- T ret1 = null;
-
- for (int i = 0; i < spanCount; i++) {
- int spanStart = starts[i];
- if (spanStart > gapstart) {
- spanStart -= gaplen;
+ if ((i & 1) != 0) {
+ // internal tree node
+ int left = leftChild(i);
+ int spanMax = mSpanMax[left];
+ if (spanMax > mGapStart) {
+ spanMax -= mGapLength;
}
- if (spanStart > queryEnd) {
- continue;
+ if (spanMax >= queryStart) {
+ count = countSpans(queryStart, queryEnd, kind, left);
}
-
- int spanEnd = ends[i];
- if (spanEnd > gapstart) {
- spanEnd -= gaplen;
+ }
+ if (i < mSpanCount) {
+ int spanStart = mSpanStarts[i];
+ if (spanStart > mGapStart) {
+ spanStart -= mGapLength;
}
- if (spanEnd < queryStart) {
- continue;
+ if (spanStart <= queryEnd) {
+ int spanEnd = mSpanEnds[i];
+ if (spanEnd > mGapStart) {
+ spanEnd -= mGapLength;
+ }
+ if (spanEnd >= queryStart &&
+ (spanStart == spanEnd || queryStart == queryEnd ||
+ (spanStart != queryEnd && spanEnd != queryStart)) &&
+ kind.isInstance(mSpans[i])) {
+ count++;
+ }
+ if ((i & 1) != 0) {
+ count += countSpans(queryStart, queryEnd, kind, rightChild(i));
+ }
}
+ }
+ return count;
+ }
- if (spanStart != spanEnd && queryStart != queryEnd) {
- if (spanStart == queryEnd)
- continue;
- if (spanEnd == queryStart)
- continue;
+ @SuppressWarnings("unchecked")
+ private <T> int getSpansRec(int queryStart, int queryEnd, Class<T> kind,
+ int i, T[] ret, int count) {
+ if ((i & 1) != 0) {
+ // internal tree node
+ int left = leftChild(i);
+ int spanMax = mSpanMax[left];
+ if (spanMax > mGapStart) {
+ spanMax -= mGapLength;
}
-
- // Expensive test, should be performed after the previous tests
- if (!kind.isInstance(spans[i])) continue;
-
- if (count == 0) {
- // Safe conversion thanks to the isInstance test above
- ret1 = (T) spans[i];
- count++;
- } else {
- if (count == 1) {
- // Safe conversion, but requires a suppressWarning
- ret = (T[]) Array.newInstance(kind, spanCount - i + 1);
- ret[0] = ret1;
- }
-
- int prio = flags[i] & SPAN_PRIORITY;
+ if (spanMax >= queryStart) {
+ count = getSpansRec(queryStart, queryEnd, kind, left, ret, count);
+ }
+ }
+ if (i >= mSpanCount) return count;
+ int spanStart = mSpanStarts[i];
+ if (spanStart > mGapStart) {
+ spanStart -= mGapLength;
+ }
+ if (spanStart <= queryEnd) {
+ int spanEnd = mSpanEnds[i];
+ if (spanEnd > mGapStart) {
+ spanEnd -= mGapLength;
+ }
+ if (spanEnd >= queryStart &&
+ (spanStart == spanEnd || queryStart == queryEnd ||
+ (spanStart != queryEnd && spanEnd != queryStart)) &&
+ kind.isInstance(mSpans[i])) {
+ int prio = mSpanFlags[i] & SPAN_PRIORITY;
if (prio != 0) {
int j;
@@ -836,32 +906,18 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
System.arraycopy(ret, j, ret, j + 1, count - j);
// Safe conversion thanks to the isInstance test above
- ret[j] = (T) spans[i];
- count++;
+ ret[j] = (T) mSpans[i];
} else {
// Safe conversion thanks to the isInstance test above
- ret[count++] = (T) spans[i];
+ ret[count] = (T) mSpans[i];
}
+ count++;
+ }
+ if (count < ret.length && (i & 1) != 0) {
+ count = getSpansRec(queryStart, queryEnd, kind, rightChild(i), ret, count);
}
}
-
- if (count == 0) {
- return ArrayUtils.emptyArray(kind);
- }
- if (count == 1) {
- // Safe conversion, but requires a suppressWarning
- ret = (T[]) Array.newInstance(kind, 1);
- ret[0] = ret1;
- return ret;
- }
- if (count == ret.length) {
- return ret;
- }
-
- // Safe conversion, but requires a suppressWarning
- T[] nret = (T[]) Array.newInstance(kind, count);
- System.arraycopy(ret, 0, nret, 0, count);
- return nret;
+ return count;
}
/**
@@ -870,30 +926,31 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
* begins or ends.
*/
public int nextSpanTransition(int start, int limit, Class kind) {
- int count = mSpanCount;
- Object[] spans = mSpans;
- int[] starts = mSpanStarts;
- int[] ends = mSpanEnds;
- int gapstart = mGapStart;
- int gaplen = mGapLength;
-
+ if (mSpanCount == 0) return limit;
if (kind == null) {
kind = Object.class;
}
+ return nextSpanTransitionRec(start, limit, kind, treeRoot());
+ }
- for (int i = 0; i < count; i++) {
- int st = starts[i];
- int en = ends[i];
-
- if (st > gapstart)
- st -= gaplen;
- if (en > gapstart)
- en -= gaplen;
-
- if (st > start && st < limit && kind.isInstance(spans[i]))
+ private int nextSpanTransitionRec(int start, int limit, Class kind, int i) {
+ if ((i & 1) != 0) {
+ // internal tree node
+ int left = leftChild(i);
+ if (resolveGap(mSpanMax[left]) > start) {
+ limit = nextSpanTransitionRec(start, limit, kind, left);
+ }
+ }
+ if (i < mSpanCount) {
+ int st = resolveGap(mSpanStarts[i]);
+ int en = resolveGap(mSpanEnds[i]);
+ if (st > start && st < limit && kind.isInstance(mSpans[i]))
limit = st;
- if (en > start && en < limit && kind.isInstance(spans[i]))
+ if (en > start && en < limit && kind.isInstance(mSpans[i]))
limit = en;
+ if (st < limit && (i & 1) != 0) {
+ limit = nextSpanTransitionRec(start, limit, kind, rightChild(i));
+ }
}
return limit;
@@ -1339,6 +1396,118 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
return hash;
}
+ // Primitives for treating span list as binary tree
+
+ // The spans (along with start and end offsets and flags) are stored in linear arrays sorted
+ // by start offset. For fast searching, there is a binary search structure imposed over these
+ // arrays. This structure is inorder traversal of a perfect binary tree, a slightly unusual
+ // but advantageous approach.
+
+ // The value-containing nodes are indexed 0 <= i < n (where n = mSpanCount), thus preserving
+ // logic that accesses the values as a contiguous array. Other balanced binary tree approaches
+ // (such as a complete binary tree) would require some shuffling of node indices.
+
+ // Basic properties of this structure: For a perfect binary tree of height m:
+ // The tree has 2^(m+1) - 1 total nodes.
+ // The root of the tree has index 2^m - 1.
+ // All leaf nodes have even index, all interior nodes odd.
+ // The height of a node of index i is the number of trailing ones in i's binary representation.
+ // The left child of a node i of height h is i - 2^(h - 1).
+ // The right child of a node i of height h is i + 2^(h - 1).
+
+ // Note that for arbitrary n, interior nodes of this tree may be >= n. Thus, the general
+ // structure of a recursive traversal of node i is:
+ // * traverse left child if i is an interior node
+ // * process i if i < n
+ // * traverse right child if i is an interior node and i < n
+
+ private int treeRoot() {
+ return Integer.highestOneBit(mSpanCount) - 1;
+ }
+
+ // (i+1) & ~i is equal to 2^(the number of trailing ones in i)
+ private static int leftChild(int i) {
+ return i - (((i + 1) & ~i) >> 1);
+ }
+
+ private static int rightChild(int i) {
+ return i + (((i + 1) & ~i) >> 1);
+ }
+
+ // The span arrays are also augmented by an mSpanMax[] array that represents an interval tree
+ // over the binary tree structure described above. For each node, the mSpanMax[] array contains
+ // the maximum value of mSpanEnds of that node and its descendants. Thus, traversals can
+ // easily reject subtrees that contain no spans overlapping the area of interest.
+
+ // Note that mSpanMax[] also has a valid valuefor interior nodes of index >= n, but which have
+ // descendants of index < n. In these cases, it simply represents the maximum span end of its
+ // descendants. This is a consequence of the perfect binary tree structure.
+ private int calcMax(int i) {
+ int max = 0;
+ if ((i & 1) != 0) {
+ // internal tree node
+ max = calcMax(leftChild(i));
+ }
+ if (i < mSpanCount) {
+ max = Math.max(max, mSpanEnds[i]);
+ if ((i & 1) != 0) {
+ max = Math.max(max, calcMax(rightChild(i)));
+ }
+ }
+ mSpanMax[i] = max;
+ return max;
+ }
+
+ // restores binary interval tree invariants after any mutation of span structure
+ private void restoreInvariants() {
+ if (mSpanCount == 0) return;
+
+ // invariant 1: span starts are nondecreasing
+
+ // This is a simple insertion sort because we expect it to be mostly sorted.
+ for (int i = 1; i < mSpanCount; i++) {
+ if (mSpanStarts[i] < mSpanStarts[i - 1]) {
+ Object span = mSpans[i];
+ int start = mSpanStarts[i];
+ int end = mSpanEnds[i];
+ int flags = mSpanFlags[i];
+ int j = i;
+ do {
+ mSpans[j] = mSpans[j - 1];
+ mSpanStarts[j] = mSpanStarts[j - 1];
+ mSpanEnds[j] = mSpanEnds[j - 1];
+ mSpanFlags[j] = mSpanFlags[j - 1];
+ j--;
+ } while (j > 0 && start < mSpanStarts[j - 1]);
+ mSpans[j] = span;
+ mSpanStarts[j] = start;
+ mSpanEnds[j] = end;
+ mSpanFlags[j] = flags;
+ invalidateIndex(j);
+ }
+ }
+
+ // invariant 2: max is max span end for each node and its descendants
+ calcMax(treeRoot());
+
+ // invariant 3: mIndexOfSpan maps spans back to indices
+ if (mIndexOfSpan == null) {
+ mIndexOfSpan = new IdentityHashMap<Object, Integer>();
+ }
+ for (int i = mLowWaterMark; i < mSpanCount; i++) {
+ Integer existing = mIndexOfSpan.get(mSpans[i]);
+ if (existing == null || existing != i) {
+ mIndexOfSpan.put(mSpans[i], i);
+ }
+ }
+ mLowWaterMark = Integer.MAX_VALUE;
+ }
+
+ // Call this on any update to mSpans[], so that mIndexOfSpan can be updated
+ private void invalidateIndex(int i) {
+ mLowWaterMark = Math.min(i, mLowWaterMark);
+ }
+
private static final InputFilter[] NO_FILTERS = new InputFilter[0];
private InputFilter[] mFilters = NO_FILTERS;
@@ -1349,9 +1518,11 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
private Object[] mSpans;
private int[] mSpanStarts;
private int[] mSpanEnds;
+ private int[] mSpanMax; // see calcMax() for an explanation of what this array stores
private int[] mSpanFlags;
private int mSpanCount;
- private int mSpanCountBeforeAdd;
+ private IdentityHashMap<Object, Integer> mIndexOfSpan;
+ private int mLowWaterMark; // indices below this have not been touched
// TODO These value are tightly related to the public SPAN_MARK/POINT values in {@link Spanned}
private static final int MARK = 1;
@@ -1363,6 +1534,7 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
private static final int START_SHIFT = 4;
// These bits are not (currently) used by SPANNED flags
+ private static final int SPAN_ADDED = 0x800;
private static final int SPAN_START_AT_START = 0x1000;
private static final int SPAN_START_AT_END = 0x2000;
private static final int SPAN_END_AT_START = 0x4000;
diff --git a/core/java/android/text/format/DateUtils.java b/core/java/android/text/format/DateUtils.java
index d0ed871..ac98e8a 100644
--- a/core/java/android/text/format/DateUtils.java
+++ b/core/java/android/text/format/DateUtils.java
@@ -28,9 +28,11 @@ import java.util.Date;
import java.util.Formatter;
import java.util.GregorianCalendar;
import java.util.Locale;
+import java.util.TimeZone;
import libcore.icu.DateIntervalFormat;
import libcore.icu.LocaleData;
+import libcore.icu.RelativeDateTimeFormatter;
/**
* This class contains various date-related utilities for creating text for things like
@@ -242,6 +244,8 @@ public class DateUtils
/**
* Returns a string describing the elapsed time since startTime.
+ * <p>
+ * The minimum timespan to report is set to {@link #MINUTE_IN_MILLIS}.
* @param startTime some time in the past.
* @return a String object containing the elapsed time.
* @see #getRelativeTimeSpanString(long, long, long)
@@ -289,69 +293,8 @@ public class DateUtils
*/
public static CharSequence getRelativeTimeSpanString(long time, long now, long minResolution,
int flags) {
- Resources r = Resources.getSystem();
- boolean abbrevRelative = (flags & (FORMAT_ABBREV_RELATIVE | FORMAT_ABBREV_ALL)) != 0;
-
- boolean past = (now >= time);
- long duration = Math.abs(now - time);
-
- int resId;
- long count;
- if (duration < MINUTE_IN_MILLIS && minResolution < MINUTE_IN_MILLIS) {
- count = duration / SECOND_IN_MILLIS;
- if (past) {
- if (abbrevRelative) {
- resId = com.android.internal.R.plurals.abbrev_num_seconds_ago;
- } else {
- resId = com.android.internal.R.plurals.num_seconds_ago;
- }
- } else {
- if (abbrevRelative) {
- resId = com.android.internal.R.plurals.abbrev_in_num_seconds;
- } else {
- resId = com.android.internal.R.plurals.in_num_seconds;
- }
- }
- } else if (duration < HOUR_IN_MILLIS && minResolution < HOUR_IN_MILLIS) {
- count = duration / MINUTE_IN_MILLIS;
- if (past) {
- if (abbrevRelative) {
- resId = com.android.internal.R.plurals.abbrev_num_minutes_ago;
- } else {
- resId = com.android.internal.R.plurals.num_minutes_ago;
- }
- } else {
- if (abbrevRelative) {
- resId = com.android.internal.R.plurals.abbrev_in_num_minutes;
- } else {
- resId = com.android.internal.R.plurals.in_num_minutes;
- }
- }
- } else if (duration < DAY_IN_MILLIS && minResolution < DAY_IN_MILLIS) {
- count = duration / HOUR_IN_MILLIS;
- if (past) {
- if (abbrevRelative) {
- resId = com.android.internal.R.plurals.abbrev_num_hours_ago;
- } else {
- resId = com.android.internal.R.plurals.num_hours_ago;
- }
- } else {
- if (abbrevRelative) {
- resId = com.android.internal.R.plurals.abbrev_in_num_hours;
- } else {
- resId = com.android.internal.R.plurals.in_num_hours;
- }
- }
- } else if (duration < WEEK_IN_MILLIS && minResolution < WEEK_IN_MILLIS) {
- return getRelativeDayString(r, time, now);
- } else {
- // We know that we won't be showing the time, so it is safe to pass
- // in a null context.
- return formatDateRange(null, time, time, flags);
- }
-
- String format = r.getQuantityString(resId, (int) count);
- return String.format(format, count);
+ return RelativeDateTimeFormatter.getRelativeTimeSpanString(Locale.getDefault(),
+ TimeZone.getDefault(), time, now, minResolution, flags);
}
/**
@@ -360,8 +303,8 @@ public class DateUtils
* <p>
* Example output strings for the US date format.
* <ul>
- * <li>3 mins ago, 10:15 AM</li>
- * <li>yesterday, 12:20 PM</li>
+ * <li>3 min. ago, 10:15 AM</li>
+ * <li>Yesterday, 12:20 PM</li>
* <li>Dec 12, 4:12 AM</li>
* <li>11/14/2007, 8:20 AM</li>
* </ul>
@@ -374,86 +317,19 @@ public class DateUtils
* @param transitionResolution the elapsed time (in milliseconds) at which
* to stop reporting relative measurements. Elapsed times greater
* than this resolution will default to normal date formatting.
- * For example, will transition from "6 days ago" to "Dec 12"
+ * For example, will transition from "7 days ago" to "Dec 12"
* when using {@link #WEEK_IN_MILLIS}.
*/
public static CharSequence getRelativeDateTimeString(Context c, long time, long minResolution,
long transitionResolution, int flags) {
- Resources r = Resources.getSystem();
-
- long now = System.currentTimeMillis();
- long duration = Math.abs(now - time);
-
- // getRelativeTimeSpanString() doesn't correctly format relative dates
- // above a week or exact dates below a day, so clamp
- // transitionResolution as needed.
- if (transitionResolution > WEEK_IN_MILLIS) {
- transitionResolution = WEEK_IN_MILLIS;
- } else if (transitionResolution < DAY_IN_MILLIS) {
- transitionResolution = DAY_IN_MILLIS;
- }
-
- CharSequence timeClause = formatDateRange(c, time, time, FORMAT_SHOW_TIME);
-
- String result;
- if (duration < transitionResolution) {
- CharSequence relativeClause = getRelativeTimeSpanString(time, now, minResolution, flags);
- result = r.getString(com.android.internal.R.string.relative_time, relativeClause, timeClause);
- } else {
- CharSequence dateClause = getRelativeTimeSpanString(c, time, false);
- result = r.getString(com.android.internal.R.string.date_time, dateClause, timeClause);
- }
-
- return result;
- }
-
- /**
- * Returns a string describing a day relative to the current day. For example if the day is
- * today this function returns "Today", if the day was a week ago it returns "7 days ago", and
- * if the day is in 2 weeks it returns "in 14 days".
- *
- * @param r the resources
- * @param day the relative day to describe in UTC milliseconds
- * @param today the current time in UTC milliseconds
- */
- private static final String getRelativeDayString(Resources r, long day, long today) {
- Locale locale = r.getConfiguration().locale;
- if (locale == null) {
- locale = Locale.getDefault();
- }
-
- // TODO: use TimeZone.getOffset instead.
- Time startTime = new Time();
- startTime.set(day);
- int startDay = Time.getJulianDay(day, startTime.gmtoff);
-
- Time currentTime = new Time();
- currentTime.set(today);
- int currentDay = Time.getJulianDay(today, currentTime.gmtoff);
-
- int days = Math.abs(currentDay - startDay);
- boolean past = (today > day);
-
- // TODO: some locales name other days too, such as de_DE's "Vorgestern" (today - 2).
- if (days == 1) {
- if (past) {
- return LocaleData.get(locale).yesterday;
- } else {
- return LocaleData.get(locale).tomorrow;
- }
- } else if (days == 0) {
- return LocaleData.get(locale).today;
- }
-
- int resId;
- if (past) {
- resId = com.android.internal.R.plurals.num_days_ago;
- } else {
- resId = com.android.internal.R.plurals.in_num_days;
+ // Same reason as in formatDateRange() to explicitly indicate 12- or 24-hour format.
+ if ((flags & (FORMAT_SHOW_TIME | FORMAT_12HOUR | FORMAT_24HOUR)) == FORMAT_SHOW_TIME) {
+ flags |= DateFormat.is24HourFormat(c) ? FORMAT_24HOUR : FORMAT_12HOUR;
}
- String format = r.getQuantityString(resId, days);
- return String.format(format, days);
+ return RelativeDateTimeFormatter.getRelativeDateTimeString(Locale.getDefault(),
+ TimeZone.getDefault(), time, System.currentTimeMillis(), minResolution,
+ transitionResolution, flags);
}
private static void initFormatStrings() {
diff --git a/core/java/android/transition/ArcMotion.java b/core/java/android/transition/ArcMotion.java
index f95fb49..70dfe7f 100644
--- a/core/java/android/transition/ArcMotion.java
+++ b/core/java/android/transition/ArcMotion.java
@@ -21,7 +21,6 @@ import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Path;
import android.util.AttributeSet;
-import android.util.FloatMath;
/**
* A PathMotion that generates a curved path along an arc on an imaginary circle containing
@@ -257,7 +256,7 @@ public class ArcMotion extends PathMotion {
}
if (newArcDistance2 != 0) {
float ratio2 = newArcDistance2 / arcDist2;
- float ratio = FloatMath.sqrt(ratio2);
+ float ratio = (float) Math.sqrt(ratio2);
ex = dx + (ratio * (ex - dx));
ey = dy + (ratio * (ey - dy));
}
diff --git a/core/java/android/transition/CircularPropagation.java b/core/java/android/transition/CircularPropagation.java
index 51beb51..1e44cfa 100644
--- a/core/java/android/transition/CircularPropagation.java
+++ b/core/java/android/transition/CircularPropagation.java
@@ -16,7 +16,6 @@
package android.transition;
import android.graphics.Rect;
-import android.util.FloatMath;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
@@ -87,9 +86,9 @@ public class CircularPropagation extends VisibilityPropagation {
epicenterY = Math.round(loc[1] + (sceneRoot.getHeight() / 2)
+ sceneRoot.getTranslationY());
}
- float distance = distance(viewCenterX, viewCenterY, epicenterX, epicenterY);
- float maxDistance = distance(0, 0, sceneRoot.getWidth(), sceneRoot.getHeight());
- float distanceFraction = distance/maxDistance;
+ double distance = distance(viewCenterX, viewCenterY, epicenterX, epicenterY);
+ double maxDistance = distance(0, 0, sceneRoot.getWidth(), sceneRoot.getHeight());
+ double distanceFraction = distance/maxDistance;
long duration = transition.getDuration();
if (duration < 0) {
@@ -99,9 +98,9 @@ public class CircularPropagation extends VisibilityPropagation {
return Math.round(duration * directionMultiplier / mPropagationSpeed * distanceFraction);
}
- private static float distance(float x1, float y1, float x2, float y2) {
- float x = x2 - x1;
- float y = y2 - y1;
- return FloatMath.sqrt((x * x) + (y * y));
+ private static double distance(float x1, float y1, float x2, float y2) {
+ double x = x2 - x1;
+ double y = y2 - y1;
+ return Math.hypot(x, y);
}
}
diff --git a/core/java/android/transition/Explode.java b/core/java/android/transition/Explode.java
index 0ccdf15..788676a 100644
--- a/core/java/android/transition/Explode.java
+++ b/core/java/android/transition/Explode.java
@@ -22,7 +22,6 @@ import android.animation.TimeInterpolator;
import android.content.Context;
import android.graphics.Rect;
import android.util.AttributeSet;
-import android.util.FloatMath;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AccelerateInterpolator;
@@ -143,32 +142,29 @@ public class Explode extends Visibility {
int centerX = bounds.centerX();
int centerY = bounds.centerY();
- float xVector = centerX - focalX;
- float yVector = centerY - focalY;
+ double xVector = centerX - focalX;
+ double yVector = centerY - focalY;
if (xVector == 0 && yVector == 0) {
// Random direction when View is centered on focal View.
- xVector = (float) (Math.random() * 2) - 1;
- yVector = (float) (Math.random() * 2) - 1;
+ xVector = (Math.random() * 2) - 1;
+ yVector = (Math.random() * 2) - 1;
}
- float vectorSize = calculateDistance(xVector, yVector);
+ double vectorSize = Math.hypot(xVector, yVector);
xVector /= vectorSize;
yVector /= vectorSize;
- float maxDistance =
+ double maxDistance =
calculateMaxDistance(sceneRoot, focalX - sceneRootX, focalY - sceneRootY);
- outVector[0] = Math.round(maxDistance * xVector);
- outVector[1] = Math.round(maxDistance * yVector);
+ outVector[0] = (int) Math.round(maxDistance * xVector);
+ outVector[1] = (int) Math.round(maxDistance * yVector);
}
- private static float calculateMaxDistance(View sceneRoot, int focalX, int focalY) {
+ private static double calculateMaxDistance(View sceneRoot, int focalX, int focalY) {
int maxX = Math.max(focalX, sceneRoot.getWidth() - focalX);
int maxY = Math.max(focalY, sceneRoot.getHeight() - focalY);
- return calculateDistance(maxX, maxY);
+ return Math.hypot(maxX, maxY);
}
- private static float calculateDistance(float x, float y) {
- return FloatMath.sqrt((x * x) + (y * y));
- }
}
diff --git a/core/java/android/transition/PatternPathMotion.java b/core/java/android/transition/PatternPathMotion.java
index a609df6..773c387 100644
--- a/core/java/android/transition/PatternPathMotion.java
+++ b/core/java/android/transition/PatternPathMotion.java
@@ -23,7 +23,6 @@ import android.graphics.Matrix;
import android.graphics.Path;
import android.graphics.PathMeasure;
import android.util.AttributeSet;
-import android.util.FloatMath;
import android.util.PathParser;
/**
@@ -119,7 +118,7 @@ public class PatternPathMotion extends PathMotion {
mTempMatrix.setTranslate(-startX, -startY);
float dx = endX - startX;
float dy = endY - startY;
- float distance = distance(dx, dy);
+ float distance = (float) Math.hypot(dx, dy);
float scale = 1 / distance;
mTempMatrix.postScale(scale, scale);
double angle = Math.atan2(dy, dx);
@@ -130,9 +129,9 @@ public class PatternPathMotion extends PathMotion {
@Override
public Path getPath(float startX, float startY, float endX, float endY) {
- float dx = endX - startX;
- float dy = endY - startY;
- float length = distance(dx, dy);
+ double dx = endX - startX;
+ double dy = endY - startY;
+ float length = (float) Math.hypot(dx, dy);
double angle = Math.atan2(dy, dx);
mTempMatrix.setScale(length, length);
@@ -143,7 +142,4 @@ public class PatternPathMotion extends PathMotion {
return path;
}
- private static float distance(float x, float y) {
- return FloatMath.sqrt((x * x) + (y * y));
- }
}
diff --git a/core/java/android/transition/SidePropagation.java b/core/java/android/transition/SidePropagation.java
index ad6c2dd..5dd1fff 100644
--- a/core/java/android/transition/SidePropagation.java
+++ b/core/java/android/transition/SidePropagation.java
@@ -16,7 +16,6 @@
package android.transition;
import android.graphics.Rect;
-import android.util.FloatMath;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
diff --git a/core/java/android/transition/Transition.java b/core/java/android/transition/Transition.java
index 2705bcf..c942042 100644
--- a/core/java/android/transition/Transition.java
+++ b/core/java/android/transition/Transition.java
@@ -1762,7 +1762,17 @@ public abstract class Transition implements Cloneable {
runAnimators();
}
- boolean areValuesChanged(TransitionValues oldValues, TransitionValues newValues) {
+ /**
+ * Returns whether transition values have changed between the start scene and the end scene
+ * (thus determining whether animation is required). The default implementation compares the
+ * property values returned from {@link #getTransitionProperties()}, or all property values if
+ * {@code getTransitionProperties()} returns null. Subclasses may override this method to
+ * provide logic more specific to their transition implementation.
+ *
+ * @param oldValues the first set of values, may be {@code null}
+ * @param newValues the second set of values, may be {@code null}
+ */
+ protected boolean areValuesChanged(TransitionValues oldValues, TransitionValues newValues) {
boolean valuesChanged = false;
// if oldValues null, then transition didn't care to stash values,
// and won't get canceled
diff --git a/core/java/android/transition/Visibility.java b/core/java/android/transition/Visibility.java
index 8779229..26dca43 100644
--- a/core/java/android/transition/Visibility.java
+++ b/core/java/android/transition/Visibility.java
@@ -182,7 +182,7 @@ public abstract class Visibility extends Transition {
return visibility == View.VISIBLE && parent != null;
}
- private VisibilityInfo getVisibilityChangeInfo(TransitionValues startValues,
+ private static VisibilityInfo getVisibilityChangeInfo(TransitionValues startValues,
TransitionValues endValues) {
final VisibilityInfo visInfo = new VisibilityInfo();
visInfo.visibilityChange = false;
@@ -484,7 +484,7 @@ public abstract class Visibility extends Transition {
}
@Override
- boolean areValuesChanged(TransitionValues oldValues, TransitionValues newValues) {
+ protected boolean areValuesChanged(TransitionValues oldValues, TransitionValues newValues) {
if (oldValues == null && newValues == null) {
return false;
}
diff --git a/core/java/android/util/AtomicFile.java b/core/java/android/util/AtomicFile.java
index a6466fc..3aa3447 100644
--- a/core/java/android/util/AtomicFile.java
+++ b/core/java/android/util/AtomicFile.java
@@ -102,7 +102,7 @@ public class AtomicFile {
str = new FileOutputStream(mBaseName);
} catch (FileNotFoundException e) {
File parent = mBaseName.getParentFile();
- if (!parent.mkdir()) {
+ if (!parent.mkdirs()) {
throw new IOException("Couldn't create directory " + mBaseName);
}
FileUtils.setPermissions(
diff --git a/core/java/android/util/DisplayMetrics.java b/core/java/android/util/DisplayMetrics.java
index c855e57..d0e5b9e 100644
--- a/core/java/android/util/DisplayMetrics.java
+++ b/core/java/android/util/DisplayMetrics.java
@@ -62,6 +62,13 @@ public class DisplayMetrics {
public static final int DENSITY_HIGH = 240;
/**
+ * Intermediate density for screens that sit between {@link #DENSITY_HIGH} (240dpi) and
+ * {@link #DENSITY_XHIGH} (320dpi). This is not a density that applications should target,
+ * instead relying on the system to scale their {@link #DENSITY_XHIGH} assets for them.
+ */
+ public static final int DENSITY_280 = 280;
+
+ /**
* Standard quantized DPI for extra-high-density screens.
*/
public static final int DENSITY_XHIGH = 320;
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 04aafc1..ad5d651 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -17109,6 +17109,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @param id The id to search for.
* @return The view that has the given id in the hierarchy or null
*/
+ @Nullable
public final View findViewById(int id) {
if (id < 0) {
return null;
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index e1cee1e..504a758 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -1208,7 +1208,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
* {@inheritDoc}
*/
public void bringChildToFront(View child) {
- int index = indexOfChild(child);
+ final int index = indexOfChild(child);
if (index >= 0) {
removeFromArray(index);
addInArray(child, mChildrenCount);
@@ -3771,7 +3771,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
* {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
*
* @param child the child view to add
- * @param index the position at which to add the child
+ * @param index the position at which to add the child or -1 to add last
* @param params the layout parameters to set on the child
*/
public void addView(View child, int index, LayoutParams params) {
@@ -3887,7 +3887,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
* If index is negative, it means put it at the end of the list.
*
* @param child the view to add to the group
- * @param index the index at which the child must be added
+ * @param index the index at which the child must be added or -1 to add last
* @param params the layout parameters to associate with the child
* @return true if the child was added, false otherwise
*/
@@ -3902,7 +3902,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
* If index is negative, it means put it at the end of the list.
*
* @param child the view to add to the group
- * @param index the index at which the child must be added
+ * @param index the index at which the child must be added or -1 to add last
* @param params the layout parameters to associate with the child
* @param preventRequestLayout if true, calling this method will not trigger a
* layout request on child
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 1456b52..8964862 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -984,6 +984,7 @@ public abstract class Window {
*
* @return The view if found or null otherwise.
*/
+ @Nullable
public View findViewById(int id) {
return getDecorView().findViewById(id);
}
diff --git a/core/java/android/view/accessibility/AccessibilityCache.java b/core/java/android/view/accessibility/AccessibilityCache.java
index 52912b1..d0dde00 100644
--- a/core/java/android/view/accessibility/AccessibilityCache.java
+++ b/core/java/android/view/accessibility/AccessibilityCache.java
@@ -40,6 +40,9 @@ final class AccessibilityCache {
private final Object mLock = new Object();
+ private long mAccessibilityFocus = AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
+ private long mInputFocus = AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
+
private final SparseArray<AccessibilityWindowInfo> mWindowCache =
new SparseArray<>();
@@ -73,9 +76,29 @@ final class AccessibilityCache {
synchronized (mLock) {
final int eventType = event.getEventType();
switch (eventType) {
- case AccessibilityEvent.TYPE_VIEW_FOCUSED:
- case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED:
- case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED:
+ case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED: {
+ if (mAccessibilityFocus != AccessibilityNodeInfo.UNDEFINED_ITEM_ID) {
+ refreshCachedNodeLocked(event.getWindowId(), mAccessibilityFocus);
+ }
+ mAccessibilityFocus = event.getSourceNodeId();
+ refreshCachedNodeLocked(event.getWindowId(), mAccessibilityFocus);
+ } break;
+
+ case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED: {
+ if (mAccessibilityFocus == event.getSourceNodeId()) {
+ refreshCachedNodeLocked(event.getWindowId(), mAccessibilityFocus);
+ mAccessibilityFocus = AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
+ }
+ } break;
+
+ case AccessibilityEvent.TYPE_VIEW_FOCUSED: {
+ if (mInputFocus != AccessibilityNodeInfo.UNDEFINED_ITEM_ID) {
+ refreshCachedNodeLocked(event.getWindowId(), mInputFocus);
+ }
+ mInputFocus = event.getSourceNodeId();
+ refreshCachedNodeLocked(event.getWindowId(), mInputFocus);
+ } break;
+
case AccessibilityEvent.TYPE_VIEW_SELECTED:
case AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED:
case AccessibilityEvent.TYPE_VIEW_CLICKED:
@@ -268,6 +291,9 @@ final class AccessibilityCache {
final int windowId = mNodeCache.keyAt(i);
clearNodesForWindowLocked(windowId);
}
+
+ mAccessibilityFocus = AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
+ mInputFocus = AccessibilityNodeInfo.UNDEFINED_ITEM_ID;
}
}
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index b56378f..325ffdd 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -494,19 +494,17 @@ public final class InputMethodManager {
mIInputContext.finishComposingText();
} catch (RemoteException e) {
}
- // Check focus again in case that "onWindowFocus" is called before
- // handling this message.
- if (mServedView != null && mServedView.hasWindowFocus()) {
- // "finishComposingText" has been already called above. So we
- // should not call mServedInputConnection.finishComposingText here.
- // Also, please note that this handler thread could be different
- // from a thread that created mServedView. That could happen
- // the current activity is running in the system process.
- // In that case, we really should not call
- // mServedInputConnection.finishComposingText.
- if (checkFocusNoStartInput(mHasBeenInactive, false)) {
- startInputInner(null, 0, 0, 0);
- }
+ }
+ // Check focus again in case that "onWindowFocus" is called before
+ // handling this message.
+ if (mServedView != null && mServedView.hasWindowFocus()) {
+ // Please note that this handler thread could be different
+ // from a thread that created mServedView. That could happen
+ // the current activity is running in the system process.
+ // In that case, we really should not call
+ // mServedInputConnection.finishComposingText.
+ if (checkFocusNoStartInput(mHasBeenInactive, false)) {
+ startInputInner(null, 0, 0, 0);
}
}
}
diff --git a/core/java/android/webkit/LegacyErrorStrings.java b/core/java/android/webkit/LegacyErrorStrings.java
index 11fc05d..60a6ee1 100644
--- a/core/java/android/webkit/LegacyErrorStrings.java
+++ b/core/java/android/webkit/LegacyErrorStrings.java
@@ -17,7 +17,6 @@
package android.webkit;
import android.content.Context;
-import android.net.http.EventHandler;
import android.util.Log;
/**
@@ -44,52 +43,52 @@ class LegacyErrorStrings {
*/
private static int getResource(int errorCode) {
switch(errorCode) {
- case EventHandler.OK:
+ case 0: /* EventHandler.OK: */
return com.android.internal.R.string.httpErrorOk;
- case EventHandler.ERROR:
+ case -1: /* EventHandler.ERROR: */
return com.android.internal.R.string.httpError;
- case EventHandler.ERROR_LOOKUP:
+ case -2: /* EventHandler.ERROR_LOOKUP: */
return com.android.internal.R.string.httpErrorLookup;
- case EventHandler.ERROR_UNSUPPORTED_AUTH_SCHEME:
+ case -3: /* EventHandler.ERROR_UNSUPPORTED_AUTH_SCHEME: */
return com.android.internal.R.string.httpErrorUnsupportedAuthScheme;
- case EventHandler.ERROR_AUTH:
+ case -4: /* EventHandler.ERROR_AUTH: */
return com.android.internal.R.string.httpErrorAuth;
- case EventHandler.ERROR_PROXYAUTH:
+ case -5: /* EventHandler.ERROR_PROXYAUTH: */
return com.android.internal.R.string.httpErrorProxyAuth;
- case EventHandler.ERROR_CONNECT:
+ case -6: /* EventHandler.ERROR_CONNECT: */
return com.android.internal.R.string.httpErrorConnect;
- case EventHandler.ERROR_IO:
+ case -7: /* EventHandler.ERROR_IO: */
return com.android.internal.R.string.httpErrorIO;
- case EventHandler.ERROR_TIMEOUT:
+ case -8: /* EventHandler.ERROR_TIMEOUT: */
return com.android.internal.R.string.httpErrorTimeout;
- case EventHandler.ERROR_REDIRECT_LOOP:
+ case -9: /* EventHandler.ERROR_REDIRECT_LOOP: */
return com.android.internal.R.string.httpErrorRedirectLoop;
- case EventHandler.ERROR_UNSUPPORTED_SCHEME:
+ case -10: /* EventHandler.ERROR_UNSUPPORTED_SCHEME: */
return com.android.internal.R.string.httpErrorUnsupportedScheme;
- case EventHandler.ERROR_FAILED_SSL_HANDSHAKE:
+ case -11: /* EventHandler.ERROR_FAILED_SSL_HANDSHAKE: */
return com.android.internal.R.string.httpErrorFailedSslHandshake;
- case EventHandler.ERROR_BAD_URL:
+ case -12: /* EventHandler.ERROR_BAD_URL: */
return com.android.internal.R.string.httpErrorBadUrl;
- case EventHandler.FILE_ERROR:
+ case -13: /* EventHandler.FILE_ERROR: */
return com.android.internal.R.string.httpErrorFile;
- case EventHandler.FILE_NOT_FOUND_ERROR:
+ case -14: /* EventHandler.FILE_NOT_FOUND_ERROR: */
return com.android.internal.R.string.httpErrorFileNotFound;
- case EventHandler.TOO_MANY_REQUESTS_ERROR:
+ case -15: /* EventHandler.TOO_MANY_REQUESTS_ERROR: */
return com.android.internal.R.string.httpErrorTooManyRequests;
default:
diff --git a/core/java/android/widget/CompoundButton.java b/core/java/android/widget/CompoundButton.java
index fede493..f2afeeb 100644
--- a/core/java/android/widget/CompoundButton.java
+++ b/core/java/android/widget/CompoundButton.java
@@ -16,6 +16,7 @@
package android.widget;
+import android.annotation.DrawableRes;
import android.annotation.Nullable;
import android.graphics.PorterDuff;
import com.android.internal.R;
@@ -50,7 +51,6 @@ import android.view.accessibility.AccessibilityNodeInfo;
*/
public abstract class CompoundButton extends Button implements Checkable {
private boolean mChecked;
- private int mButtonResource;
private boolean mBroadcasting;
private Drawable mButtonDrawable;
@@ -197,54 +197,62 @@ public abstract class CompoundButton extends Button implements Checkable {
}
/**
- * Set the button graphic to a given Drawable, identified by its resource
- * id.
+ * Sets a drawable as the compound button image given its resource
+ * identifier.
*
- * @param resid the resource id of the drawable to use as the button
- * graphic
+ * @param resId the resource identifier of the drawable
+ * @attr ref android.R.styleable#CompoundButton_button
*/
- public void setButtonDrawable(int resid) {
- if (resid != 0 && resid == mButtonResource) {
- return;
- }
-
- mButtonResource = resid;
-
- Drawable d = null;
- if (mButtonResource != 0) {
- d = getContext().getDrawable(mButtonResource);
+ public void setButtonDrawable(@DrawableRes int resId) {
+ final Drawable d;
+ if (resId != 0) {
+ d = getContext().getDrawable(resId);
+ } else {
+ d = null;
}
setButtonDrawable(d);
}
/**
- * Set the button graphic to a given Drawable
+ * Sets a drawable as the compound button image.
*
- * @param d The Drawable to use as the button graphic
+ * @param drawable the drawable to set
+ * @attr ref android.R.styleable#CompoundButton_button
*/
- public void setButtonDrawable(Drawable d) {
- if (mButtonDrawable != d) {
+ @Nullable
+ public void setButtonDrawable(@Nullable Drawable drawable) {
+ if (mButtonDrawable != drawable) {
if (mButtonDrawable != null) {
mButtonDrawable.setCallback(null);
unscheduleDrawable(mButtonDrawable);
}
- mButtonDrawable = d;
+ mButtonDrawable = drawable;
- if (d != null) {
- d.setCallback(this);
- d.setLayoutDirection(getLayoutDirection());
- if (d.isStateful()) {
- d.setState(getDrawableState());
+ if (drawable != null) {
+ drawable.setCallback(this);
+ drawable.setLayoutDirection(getLayoutDirection());
+ if (drawable.isStateful()) {
+ drawable.setState(getDrawableState());
}
- d.setVisible(getVisibility() == VISIBLE, false);
- setMinHeight(d.getIntrinsicHeight());
+ drawable.setVisible(getVisibility() == VISIBLE, false);
+ setMinHeight(drawable.getIntrinsicHeight());
applyButtonTint();
}
}
}
/**
+ * @return the drawable used as the compound button image
+ * @see #setButtonDrawable(Drawable)
+ * @see #setButtonDrawable(int)
+ */
+ @Nullable
+ public Drawable getButtonDrawable() {
+ return mButtonDrawable;
+ }
+
+ /**
* Applies a tint to the button drawable. Does not modify the current tint
* mode, which is {@link PorterDuff.Mode#SRC_IN} by default.
* <p>
diff --git a/core/java/android/widget/EdgeEffect.java b/core/java/android/widget/EdgeEffect.java
index 6925756..391347e 100644
--- a/core/java/android/widget/EdgeEffect.java
+++ b/core/java/android/widget/EdgeEffect.java
@@ -24,7 +24,6 @@ import android.graphics.Rect;
import android.content.Context;
import android.graphics.Canvas;
-import android.util.FloatMath;
import android.view.animation.AnimationUtils;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
@@ -220,8 +219,8 @@ public class EdgeEffect {
if (mPullDistance == 0) {
mGlowScaleY = mGlowScaleYStart = 0;
} else {
- final float scale = Math.max(0, 1 - 1 /
- FloatMath.sqrt(Math.abs(mPullDistance) * mBounds.height()) - 0.3f) / 0.7f;
+ final float scale = (float) (Math.max(0, 1 - 1 /
+ Math.sqrt(Math.abs(mPullDistance) * mBounds.height()) - 0.3d) / 0.7d);
mGlowScaleY = mGlowScaleYStart = scale;
}
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index d5166f3..4752594 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -1352,6 +1352,9 @@ public class Editor {
searchStartIndex);
// Note how dynamic layout's internal block indices get updated from Editor
blockIndices[i] = blockIndex;
+ if (mTextDisplayLists[blockIndex] != null) {
+ mTextDisplayLists[blockIndex].isDirty = true;
+ }
searchStartIndex = blockIndex + 1;
}
@@ -1388,6 +1391,7 @@ public class Editor {
// brings this range of text back to the top left corner of the viewport
hardwareCanvas.translate(-left, -top);
layout.drawText(hardwareCanvas, blockBeginLine, blockEndLine);
+ mTextDisplayLists[blockIndex].isDirty = false;
// No need to untranslate, previous context is popped after
// drawDisplayList
} finally {
diff --git a/core/java/com/android/internal/http/multipart/ByteArrayPartSource.java b/core/java/com/android/internal/http/multipart/ByteArrayPartSource.java
deleted file mode 100644
index faaac7f..0000000
--- a/core/java/com/android/internal/http/multipart/ByteArrayPartSource.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//httpclient/src/java/org/apache/commons/httpclient/methods/multipart/ByteArrayPartSource.java,v 1.7 2004/04/18 23:51:37 jsdever Exp $
- * $Revision: 480424 $
- * $Date: 2006-11-29 06:56:49 +0100 (Wed, 29 Nov 2006) $
- *
- * ====================================================================
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- * ====================================================================
- *
- * This software consists of voluntary contributions made by many
- * individuals on behalf of the Apache Software Foundation. For more
- * information on the Apache Software Foundation, please see
- * <http://www.apache.org/>.
- *
- */
-
-package com.android.internal.http.multipart;
-
-import java.io.ByteArrayInputStream;
-import java.io.InputStream;
-
-/**
- * A PartSource that reads from a byte array. This class should be used when
- * the data to post is already loaded into memory.
- *
- * @author <a href="mailto:becke@u.washington.edu">Michael Becke</a>
- *
- * @since 2.0
- */
-public class ByteArrayPartSource implements PartSource {
-
- /** Name of the source file. */
- private String fileName;
-
- /** Byte array of the source file. */
- private byte[] bytes;
-
- /**
- * Constructor for ByteArrayPartSource.
- *
- * @param fileName the name of the file these bytes represent
- * @param bytes the content of this part
- */
- public ByteArrayPartSource(String fileName, byte[] bytes) {
-
- this.fileName = fileName;
- this.bytes = bytes;
-
- }
-
- /**
- * @see PartSource#getLength()
- */
- public long getLength() {
- return bytes.length;
- }
-
- /**
- * @see PartSource#getFileName()
- */
- public String getFileName() {
- return fileName;
- }
-
- /**
- * @see PartSource#createInputStream()
- */
- public InputStream createInputStream() {
- return new ByteArrayInputStream(bytes);
- }
-
-}
diff --git a/core/java/com/android/internal/http/multipart/FilePart.java b/core/java/com/android/internal/http/multipart/FilePart.java
deleted file mode 100644
index 45e4be6..0000000
--- a/core/java/com/android/internal/http/multipart/FilePart.java
+++ /dev/null
@@ -1,259 +0,0 @@
-/*
- * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//httpclient/src/java/org/apache/commons/httpclient/methods/multipart/FilePart.java,v 1.19 2004/04/18 23:51:37 jsdever Exp $
- * $Revision: 480424 $
- * $Date: 2006-11-29 06:56:49 +0100 (Wed, 29 Nov 2006) $
- *
- * ====================================================================
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- * ====================================================================
- *
- * This software consists of voluntary contributions made by many
- * individuals on behalf of the Apache Software Foundation. For more
- * information on the Apache Software Foundation, please see
- * <http://www.apache.org/>.
- *
- */
-
-package com.android.internal.http.multipart;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import org.apache.http.util.EncodingUtils;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-/**
- * This class implements a part of a Multipart post object that
- * consists of a file.
- *
- * @author <a href="mailto:mattalbright@yahoo.com">Matthew Albright</a>
- * @author <a href="mailto:jsdever@apache.org">Jeff Dever</a>
- * @author <a href="mailto:adrian@ephox.com">Adrian Sutton</a>
- * @author <a href="mailto:becke@u.washington.edu">Michael Becke</a>
- * @author <a href="mailto:mdiggory@latte.harvard.edu">Mark Diggory</a>
- * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
- * @author <a href="mailto:oleg@ural.ru">Oleg Kalnichevski</a>
- *
- * @since 2.0
- *
- * @deprecated Please use {@link java.net.URLConnection} and friends instead.
- * The Apache HTTP client is no longer maintained and may be removed in a future
- * release. Please visit <a href="http://android-developers.blogspot.com/2011/09/androids-http-clients.html">this webpage</a>
- * for further details.
- */
-@Deprecated
-public class FilePart extends PartBase {
-
- /** Default content encoding of file attachments. */
- public static final String DEFAULT_CONTENT_TYPE = "application/octet-stream";
-
- /** Default charset of file attachments. */
- public static final String DEFAULT_CHARSET = "ISO-8859-1";
-
- /** Default transfer encoding of file attachments. */
- public static final String DEFAULT_TRANSFER_ENCODING = "binary";
-
- /** Log object for this class. */
- private static final Log LOG = LogFactory.getLog(FilePart.class);
-
- /** Attachment's file name */
- protected static final String FILE_NAME = "; filename=";
-
- /** Attachment's file name as a byte array */
- private static final byte[] FILE_NAME_BYTES =
- EncodingUtils.getAsciiBytes(FILE_NAME);
-
- /** Source of the file part. */
- private PartSource source;
-
- /**
- * FilePart Constructor.
- *
- * @param name the name for this part
- * @param partSource the source for this part
- * @param contentType the content type for this part, if <code>null</code> the
- * {@link #DEFAULT_CONTENT_TYPE default} is used
- * @param charset the charset encoding for this part, if <code>null</code> the
- * {@link #DEFAULT_CHARSET default} is used
- */
- public FilePart(String name, PartSource partSource, String contentType, String charset) {
-
- super(
- name,
- contentType == null ? DEFAULT_CONTENT_TYPE : contentType,
- charset == null ? "ISO-8859-1" : charset,
- DEFAULT_TRANSFER_ENCODING
- );
-
- if (partSource == null) {
- throw new IllegalArgumentException("Source may not be null");
- }
- this.source = partSource;
- }
-
- /**
- * FilePart Constructor.
- *
- * @param name the name for this part
- * @param partSource the source for this part
- */
- public FilePart(String name, PartSource partSource) {
- this(name, partSource, null, null);
- }
-
- /**
- * FilePart Constructor.
- *
- * @param name the name of the file part
- * @param file the file to post
- *
- * @throws FileNotFoundException if the <i>file</i> is not a normal
- * file or if it is not readable.
- */
- public FilePart(String name, File file)
- throws FileNotFoundException {
- this(name, new FilePartSource(file), null, null);
- }
-
- /**
- * FilePart Constructor.
- *
- * @param name the name of the file part
- * @param file the file to post
- * @param contentType the content type for this part, if <code>null</code> the
- * {@link #DEFAULT_CONTENT_TYPE default} is used
- * @param charset the charset encoding for this part, if <code>null</code> the
- * {@link #DEFAULT_CHARSET default} is used
- *
- * @throws FileNotFoundException if the <i>file</i> is not a normal
- * file or if it is not readable.
- */
- public FilePart(String name, File file, String contentType, String charset)
- throws FileNotFoundException {
- this(name, new FilePartSource(file), contentType, charset);
- }
-
- /**
- * FilePart Constructor.
- *
- * @param name the name of the file part
- * @param fileName the file name
- * @param file the file to post
- *
- * @throws FileNotFoundException if the <i>file</i> is not a normal
- * file or if it is not readable.
- */
- public FilePart(String name, String fileName, File file)
- throws FileNotFoundException {
- this(name, new FilePartSource(fileName, file), null, null);
- }
-
- /**
- * FilePart Constructor.
- *
- * @param name the name of the file part
- * @param fileName the file name
- * @param file the file to post
- * @param contentType the content type for this part, if <code>null</code> the
- * {@link #DEFAULT_CONTENT_TYPE default} is used
- * @param charset the charset encoding for this part, if <code>null</code> the
- * {@link #DEFAULT_CHARSET default} is used
- *
- * @throws FileNotFoundException if the <i>file</i> is not a normal
- * file or if it is not readable.
- */
- public FilePart(String name, String fileName, File file, String contentType, String charset)
- throws FileNotFoundException {
- this(name, new FilePartSource(fileName, file), contentType, charset);
- }
-
- /**
- * Write the disposition header to the output stream
- * @param out The output stream
- * @throws IOException If an IO problem occurs
- * @see Part#sendDispositionHeader(OutputStream)
- */
- @Override
- protected void sendDispositionHeader(OutputStream out)
- throws IOException {
- LOG.trace("enter sendDispositionHeader(OutputStream out)");
- super.sendDispositionHeader(out);
- String filename = this.source.getFileName();
- if (filename != null) {
- out.write(FILE_NAME_BYTES);
- out.write(QUOTE_BYTES);
- out.write(EncodingUtils.getAsciiBytes(filename));
- out.write(QUOTE_BYTES);
- }
- }
-
- /**
- * Write the data in "source" to the specified stream.
- * @param out The output stream.
- * @throws IOException if an IO problem occurs.
- * @see Part#sendData(OutputStream)
- */
- @Override
- protected void sendData(OutputStream out) throws IOException {
- LOG.trace("enter sendData(OutputStream out)");
- if (lengthOfData() == 0) {
-
- // this file contains no data, so there is nothing to send.
- // we don't want to create a zero length buffer as this will
- // cause an infinite loop when reading.
- LOG.debug("No data to send.");
- return;
- }
-
- byte[] tmp = new byte[4096];
- InputStream instream = source.createInputStream();
- try {
- int len;
- while ((len = instream.read(tmp)) >= 0) {
- out.write(tmp, 0, len);
- }
- } finally {
- // we're done with the stream, close it
- instream.close();
- }
- }
-
- /**
- * Returns the source of the file part.
- *
- * @return The source.
- */
- protected PartSource getSource() {
- LOG.trace("enter getSource()");
- return this.source;
- }
-
- /**
- * Return the length of the data.
- * @return The length.
- * @see Part#lengthOfData()
- */
- @Override
- protected long lengthOfData() {
- LOG.trace("enter lengthOfData()");
- return source.getLength();
- }
-
-}
diff --git a/core/java/com/android/internal/http/multipart/FilePartSource.java b/core/java/com/android/internal/http/multipart/FilePartSource.java
deleted file mode 100644
index eb5cc0f..0000000
--- a/core/java/com/android/internal/http/multipart/FilePartSource.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//httpclient/src/java/org/apache/commons/httpclient/methods/multipart/FilePartSource.java,v 1.10 2004/04/18 23:51:37 jsdever Exp $
- * $Revision: 480424 $
- * $Date: 2006-11-29 06:56:49 +0100 (Wed, 29 Nov 2006) $
- *
- * ====================================================================
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- * ====================================================================
- *
- * This software consists of voluntary contributions made by many
- * individuals on behalf of the Apache Software Foundation. For more
- * information on the Apache Software Foundation, please see
- * <http://www.apache.org/>.
- *
- */
-
-package com.android.internal.http.multipart;
-
-import java.io.ByteArrayInputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
-
-/**
- * A PartSource that reads from a File.
- *
- * @author <a href="mailto:becke@u.washington.edu">Michael Becke</a>
- * @author <a href="mailto:mdiggory@latte.harvard.edu">Mark Diggory</a>
- * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
- *
- * @since 2.0
- */
-public class FilePartSource implements PartSource {
-
- /** File part file. */
- private File file = null;
-
- /** File part file name. */
- private String fileName = null;
-
- /**
- * Constructor for FilePartSource.
- *
- * @param file the FilePart source File.
- *
- * @throws FileNotFoundException if the file does not exist or
- * cannot be read
- */
- public FilePartSource(File file) throws FileNotFoundException {
- this.file = file;
- if (file != null) {
- if (!file.isFile()) {
- throw new FileNotFoundException("File is not a normal file.");
- }
- if (!file.canRead()) {
- throw new FileNotFoundException("File is not readable.");
- }
- this.fileName = file.getName();
- }
- }
-
- /**
- * Constructor for FilePartSource.
- *
- * @param fileName the file name of the FilePart
- * @param file the source File for the FilePart
- *
- * @throws FileNotFoundException if the file does not exist or
- * cannot be read
- */
- public FilePartSource(String fileName, File file)
- throws FileNotFoundException {
- this(file);
- if (fileName != null) {
- this.fileName = fileName;
- }
- }
-
- /**
- * Return the length of the file
- * @return the length of the file.
- * @see PartSource#getLength()
- */
- public long getLength() {
- if (this.file != null) {
- return this.file.length();
- } else {
- return 0;
- }
- }
-
- /**
- * Return the current filename
- * @return the filename.
- * @see PartSource#getFileName()
- */
- public String getFileName() {
- return (fileName == null) ? "noname" : fileName;
- }
-
- /**
- * Return a new {@link FileInputStream} for the current filename.
- * @return the new input stream.
- * @throws IOException If an IO problem occurs.
- * @see PartSource#createInputStream()
- */
- public InputStream createInputStream() throws IOException {
- if (this.file != null) {
- return new FileInputStream(this.file);
- } else {
- return new ByteArrayInputStream(new byte[] {});
- }
- }
-
-}
diff --git a/core/java/com/android/internal/http/multipart/MultipartEntity.java b/core/java/com/android/internal/http/multipart/MultipartEntity.java
deleted file mode 100644
index 5319251..0000000
--- a/core/java/com/android/internal/http/multipart/MultipartEntity.java
+++ /dev/null
@@ -1,236 +0,0 @@
-/*
- * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//httpclient/src/java/org/apache/commons/httpclient/methods/multipart/MultipartRequestEntity.java,v 1.1 2004/10/06 03:39:59 mbecke Exp $
- * $Revision: 502647 $
- * $Date: 2007-02-02 17:22:54 +0100 (Fri, 02 Feb 2007) $
- *
- * ====================================================================
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- * ====================================================================
- *
- * This software consists of voluntary contributions made by many
- * individuals on behalf of the Apache Software Foundation. For more
- * information on the Apache Software Foundation, please see
- * <http://www.apache.org/>.
- *
- */
-
-package com.android.internal.http.multipart;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.Random;
-
-import org.apache.http.Header;
-import org.apache.http.entity.AbstractHttpEntity;
-import org.apache.http.message.BasicHeader;
-import org.apache.http.params.HttpParams;
-import org.apache.http.protocol.HTTP;
-import org.apache.http.util.EncodingUtils;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-/**
- * Implements a request entity suitable for an HTTP multipart POST method.
- * <p>
- * The HTTP multipart POST method is defined in section 3.3 of
- * <a href="http://www.ietf.org/rfc/rfc1867.txt">RFC1867</a>:
- * <blockquote>
- * The media-type multipart/form-data follows the rules of all multipart
- * MIME data streams as outlined in RFC 1521. The multipart/form-data contains
- * a series of parts. Each part is expected to contain a content-disposition
- * header where the value is "form-data" and a name attribute specifies
- * the field name within the form, e.g., 'content-disposition: form-data;
- * name="xxxxx"', where xxxxx is the field name corresponding to that field.
- * Field names originally in non-ASCII character sets may be encoded using
- * the method outlined in RFC 1522.
- * </blockquote>
- * </p>
- * <p>This entity is designed to be used in conjunction with the
- * {@link org.apache.http.HttpRequest} to provide
- * multipart posts. Example usage:</p>
- * <pre>
- * File f = new File("/path/fileToUpload.txt");
- * HttpRequest request = new HttpRequest("http://host/some_path");
- * Part[] parts = {
- * new StringPart("param_name", "value"),
- * new FilePart(f.getName(), f)
- * };
- * filePost.setEntity(
- * new MultipartRequestEntity(parts, filePost.getParams())
- * );
- * HttpClient client = new HttpClient();
- * int status = client.executeMethod(filePost);
- * </pre>
- *
- * @since 3.0
- *
- * @deprecated Please use {@link java.net.URLConnection} and friends instead.
- * The Apache HTTP client is no longer maintained and may be removed in a future
- * release. Please visit <a href="http://android-developers.blogspot.com/2011/09/androids-http-clients.html">this webpage</a>
- * for further details.
- */
-@Deprecated
-public class MultipartEntity extends AbstractHttpEntity {
-
- private static final Log log = LogFactory.getLog(MultipartEntity.class);
-
- /** The Content-Type for multipart/form-data. */
- private static final String MULTIPART_FORM_CONTENT_TYPE = "multipart/form-data";
-
- /**
- * Sets the value to use as the multipart boundary.
- * <p>
- * This parameter expects a value if type {@link String}.
- * </p>
- */
- public static final String MULTIPART_BOUNDARY = "http.method.multipart.boundary";
-
- /**
- * The pool of ASCII chars to be used for generating a multipart boundary.
- */
- private static byte[] MULTIPART_CHARS = EncodingUtils.getAsciiBytes(
- "-_1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
-
- /**
- * Generates a random multipart boundary string.
- */
- private static byte[] generateMultipartBoundary() {
- Random rand = new Random();
- byte[] bytes = new byte[rand.nextInt(11) + 30]; // a random size from 30 to 40
- for (int i = 0; i < bytes.length; i++) {
- bytes[i] = MULTIPART_CHARS[rand.nextInt(MULTIPART_CHARS.length)];
- }
- return bytes;
- }
-
- /** The MIME parts as set by the constructor */
- protected Part[] parts;
-
- private byte[] multipartBoundary;
-
- private HttpParams params;
-
- private boolean contentConsumed = false;
-
- /**
- * Creates a new multipart entity containing the given parts.
- * @param parts The parts to include.
- * @param params The params of the HttpMethod using this entity.
- */
- public MultipartEntity(Part[] parts, HttpParams params) {
- if (parts == null) {
- throw new IllegalArgumentException("parts cannot be null");
- }
- if (params == null) {
- throw new IllegalArgumentException("params cannot be null");
- }
- this.parts = parts;
- this.params = params;
- }
-
- public MultipartEntity(Part[] parts) {
- setContentType(MULTIPART_FORM_CONTENT_TYPE);
- if (parts == null) {
- throw new IllegalArgumentException("parts cannot be null");
- }
- this.parts = parts;
- this.params = null;
- }
-
- /**
- * Returns the MIME boundary string that is used to demarcate boundaries of
- * this part. The first call to this method will implicitly create a new
- * boundary string. To create a boundary string first the
- * HttpMethodParams.MULTIPART_BOUNDARY parameter is considered. Otherwise
- * a random one is generated.
- *
- * @return The boundary string of this entity in ASCII encoding.
- */
- protected byte[] getMultipartBoundary() {
- if (multipartBoundary == null) {
- String temp = null;
- if (params != null) {
- temp = (String) params.getParameter(MULTIPART_BOUNDARY);
- }
- if (temp != null) {
- multipartBoundary = EncodingUtils.getAsciiBytes(temp);
- } else {
- multipartBoundary = generateMultipartBoundary();
- }
- }
- return multipartBoundary;
- }
-
- /**
- * Returns <code>true</code> if all parts are repeatable, <code>false</code> otherwise.
- */
- public boolean isRepeatable() {
- for (int i = 0; i < parts.length; i++) {
- if (!parts[i].isRepeatable()) {
- return false;
- }
- }
- return true;
- }
-
- /* (non-Javadoc)
- */
- public void writeTo(OutputStream out) throws IOException {
- Part.sendParts(out, parts, getMultipartBoundary());
- }
- /* (non-Javadoc)
- * @see org.apache.commons.http.AbstractHttpEntity.#getContentType()
- */
- @Override
- public Header getContentType() {
- StringBuffer buffer = new StringBuffer(MULTIPART_FORM_CONTENT_TYPE);
- buffer.append("; boundary=");
- buffer.append(EncodingUtils.getAsciiString(getMultipartBoundary()));
- return new BasicHeader(HTTP.CONTENT_TYPE, buffer.toString());
-
- }
-
- /* (non-Javadoc)
- */
- public long getContentLength() {
- try {
- return Part.getLengthOfParts(parts, getMultipartBoundary());
- } catch (Exception e) {
- log.error("An exception occurred while getting the length of the parts", e);
- return 0;
- }
- }
-
- public InputStream getContent() throws IOException, IllegalStateException {
- if(!isRepeatable() && this.contentConsumed ) {
- throw new IllegalStateException("Content has been consumed");
- }
- this.contentConsumed = true;
-
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- Part.sendParts(baos, this.parts, this.multipartBoundary);
- ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
- return bais;
- }
-
- public boolean isStreaming() {
- return false;
- }
-}
diff --git a/core/java/com/android/internal/http/multipart/Part.java b/core/java/com/android/internal/http/multipart/Part.java
deleted file mode 100644
index 1d66dc6..0000000
--- a/core/java/com/android/internal/http/multipart/Part.java
+++ /dev/null
@@ -1,445 +0,0 @@
-/*
- * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//httpclient/src/java/org/apache/commons/httpclient/methods/multipart/Part.java,v 1.16 2005/01/14 21:16:40 olegk Exp $
- * $Revision: 480424 $
- * $Date: 2006-11-29 06:56:49 +0100 (Wed, 29 Nov 2006) $
- *
- * ====================================================================
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- * ====================================================================
- *
- * This software consists of voluntary contributions made by many
- * individuals on behalf of the Apache Software Foundation. For more
- * information on the Apache Software Foundation, please see
- * <http://www.apache.org/>.
- *
- */
-
-package com.android.internal.http.multipart;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-
-import org.apache.http.util.EncodingUtils;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-/**
- * Abstract class for one Part of a multipart post object.
- *
- * @author <a href="mailto:mattalbright@yahoo.com">Matthew Albright</a>
- * @author <a href="mailto:jsdever@apache.org">Jeff Dever</a>
- * @author <a href="mailto:adrian@ephox.com">Adrian Sutton</a>
- * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
- * @author <a href="mailto:oleg@ural.ru">Oleg Kalnichevski</a>
- *
- * @since 2.0
- *
- * @deprecated Please use {@link java.net.URLConnection} and friends instead.
- * The Apache HTTP client is no longer maintained and may be removed in a future
- * release. Please visit <a href="http://android-developers.blogspot.com/2011/09/androids-http-clients.html">this webpage</a>
- * for further details.
- */
-@Deprecated
-public abstract class Part {
-
- /** Log object for this class. */
- private static final Log LOG = LogFactory.getLog(Part.class);
-
- /**
- * The boundary
- * @deprecated use {@link org.apache.http.client.methods.multipart#MULTIPART_BOUNDARY}
- */
- protected static final String BOUNDARY = "----------------314159265358979323846";
-
- /**
- * The boundary as a byte array.
- * @deprecated
- */
- protected static final byte[] BOUNDARY_BYTES = EncodingUtils.getAsciiBytes(BOUNDARY);
-
- /**
- * The default boundary to be used if {@link #setPartBoundary(byte[])} has not
- * been called.
- */
- private static final byte[] DEFAULT_BOUNDARY_BYTES = BOUNDARY_BYTES;
-
- /** Carriage return/linefeed */
- protected static final String CRLF = "\r\n";
-
- /** Carriage return/linefeed as a byte array */
- protected static final byte[] CRLF_BYTES = EncodingUtils.getAsciiBytes(CRLF);
-
- /** Content dispostion characters */
- protected static final String QUOTE = "\"";
-
- /** Content dispostion as a byte array */
- protected static final byte[] QUOTE_BYTES =
- EncodingUtils.getAsciiBytes(QUOTE);
-
- /** Extra characters */
- protected static final String EXTRA = "--";
-
- /** Extra characters as a byte array */
- protected static final byte[] EXTRA_BYTES =
- EncodingUtils.getAsciiBytes(EXTRA);
-
- /** Content dispostion characters */
- protected static final String CONTENT_DISPOSITION = "Content-Disposition: form-data; name=";
-
- /** Content dispostion as a byte array */
- protected static final byte[] CONTENT_DISPOSITION_BYTES =
- EncodingUtils.getAsciiBytes(CONTENT_DISPOSITION);
-
- /** Content type header */
- protected static final String CONTENT_TYPE = "Content-Type: ";
-
- /** Content type header as a byte array */
- protected static final byte[] CONTENT_TYPE_BYTES =
- EncodingUtils.getAsciiBytes(CONTENT_TYPE);
-
- /** Content charset */
- protected static final String CHARSET = "; charset=";
-
- /** Content charset as a byte array */
- protected static final byte[] CHARSET_BYTES =
- EncodingUtils.getAsciiBytes(CHARSET);
-
- /** Content type header */
- protected static final String CONTENT_TRANSFER_ENCODING = "Content-Transfer-Encoding: ";
-
- /** Content type header as a byte array */
- protected static final byte[] CONTENT_TRANSFER_ENCODING_BYTES =
- EncodingUtils.getAsciiBytes(CONTENT_TRANSFER_ENCODING);
-
- /**
- * Return the boundary string.
- * @return the boundary string
- * @deprecated uses a constant string. Rather use {@link #getPartBoundary}
- */
- public static String getBoundary() {
- return BOUNDARY;
- }
-
- /**
- * The ASCII bytes to use as the multipart boundary.
- */
- private byte[] boundaryBytes;
-
- /**
- * Return the name of this part.
- * @return The name.
- */
- public abstract String getName();
-
- /**
- * Returns the content type of this part.
- * @return the content type, or <code>null</code> to exclude the content type header
- */
- public abstract String getContentType();
-
- /**
- * Return the character encoding of this part.
- * @return the character encoding, or <code>null</code> to exclude the character
- * encoding header
- */
- public abstract String getCharSet();
-
- /**
- * Return the transfer encoding of this part.
- * @return the transfer encoding, or <code>null</code> to exclude the transfer encoding header
- */
- public abstract String getTransferEncoding();
-
- /**
- * Gets the part boundary to be used.
- * @return the part boundary as an array of bytes.
- *
- * @since 3.0
- */
- protected byte[] getPartBoundary() {
- if (boundaryBytes == null) {
- // custom boundary bytes have not been set, use the default.
- return DEFAULT_BOUNDARY_BYTES;
- } else {
- return boundaryBytes;
- }
- }
-
- /**
- * Sets the part boundary. Only meant to be used by
- * {@link Part#sendParts(OutputStream, Part[], byte[])}
- * and {@link Part#getLengthOfParts(Part[], byte[])}
- * @param boundaryBytes An array of ASCII bytes.
- * @since 3.0
- */
- void setPartBoundary(byte[] boundaryBytes) {
- this.boundaryBytes = boundaryBytes;
- }
-
- /**
- * Tests if this part can be sent more than once.
- * @return <code>true</code> if {@link #sendData(OutputStream)} can be successfully called
- * more than once.
- * @since 3.0
- */
- public boolean isRepeatable() {
- return true;
- }
-
- /**
- * Write the start to the specified output stream
- * @param out The output stream
- * @throws IOException If an IO problem occurs.
- */
- protected void sendStart(OutputStream out) throws IOException {
- LOG.trace("enter sendStart(OutputStream out)");
- out.write(EXTRA_BYTES);
- out.write(getPartBoundary());
- out.write(CRLF_BYTES);
- }
-
- /**
- * Write the content disposition header to the specified output stream
- *
- * @param out The output stream
- * @throws IOException If an IO problem occurs.
- */
- protected void sendDispositionHeader(OutputStream out) throws IOException {
- LOG.trace("enter sendDispositionHeader(OutputStream out)");
- out.write(CONTENT_DISPOSITION_BYTES);
- out.write(QUOTE_BYTES);
- out.write(EncodingUtils.getAsciiBytes(getName()));
- out.write(QUOTE_BYTES);
- }
-
- /**
- * Write the content type header to the specified output stream
- * @param out The output stream
- * @throws IOException If an IO problem occurs.
- */
- protected void sendContentTypeHeader(OutputStream out) throws IOException {
- LOG.trace("enter sendContentTypeHeader(OutputStream out)");
- String contentType = getContentType();
- if (contentType != null) {
- out.write(CRLF_BYTES);
- out.write(CONTENT_TYPE_BYTES);
- out.write(EncodingUtils.getAsciiBytes(contentType));
- String charSet = getCharSet();
- if (charSet != null) {
- out.write(CHARSET_BYTES);
- out.write(EncodingUtils.getAsciiBytes(charSet));
- }
- }
- }
-
- /**
- * Write the content transfer encoding header to the specified
- * output stream
- *
- * @param out The output stream
- * @throws IOException If an IO problem occurs.
- */
- protected void sendTransferEncodingHeader(OutputStream out) throws IOException {
- LOG.trace("enter sendTransferEncodingHeader(OutputStream out)");
- String transferEncoding = getTransferEncoding();
- if (transferEncoding != null) {
- out.write(CRLF_BYTES);
- out.write(CONTENT_TRANSFER_ENCODING_BYTES);
- out.write(EncodingUtils.getAsciiBytes(transferEncoding));
- }
- }
-
- /**
- * Write the end of the header to the output stream
- * @param out The output stream
- * @throws IOException If an IO problem occurs.
- */
- protected void sendEndOfHeader(OutputStream out) throws IOException {
- LOG.trace("enter sendEndOfHeader(OutputStream out)");
- out.write(CRLF_BYTES);
- out.write(CRLF_BYTES);
- }
-
- /**
- * Write the data to the specified output stream
- * @param out The output stream
- * @throws IOException If an IO problem occurs.
- */
- protected abstract void sendData(OutputStream out) throws IOException;
-
- /**
- * Return the length of the main content
- *
- * @return long The length.
- * @throws IOException If an IO problem occurs
- */
- protected abstract long lengthOfData() throws IOException;
-
- /**
- * Write the end data to the output stream.
- * @param out The output stream
- * @throws IOException If an IO problem occurs.
- */
- protected void sendEnd(OutputStream out) throws IOException {
- LOG.trace("enter sendEnd(OutputStream out)");
- out.write(CRLF_BYTES);
- }
-
- /**
- * Write all the data to the output stream.
- * If you override this method make sure to override
- * #length() as well
- *
- * @param out The output stream
- * @throws IOException If an IO problem occurs.
- */
- public void send(OutputStream out) throws IOException {
- LOG.trace("enter send(OutputStream out)");
- sendStart(out);
- sendDispositionHeader(out);
- sendContentTypeHeader(out);
- sendTransferEncodingHeader(out);
- sendEndOfHeader(out);
- sendData(out);
- sendEnd(out);
- }
-
-
- /**
- * Return the full length of all the data.
- * If you override this method make sure to override
- * #send(OutputStream) as well
- *
- * @return long The length.
- * @throws IOException If an IO problem occurs
- */
- public long length() throws IOException {
- LOG.trace("enter length()");
- if (lengthOfData() < 0) {
- return -1;
- }
- ByteArrayOutputStream overhead = new ByteArrayOutputStream();
- sendStart(overhead);
- sendDispositionHeader(overhead);
- sendContentTypeHeader(overhead);
- sendTransferEncodingHeader(overhead);
- sendEndOfHeader(overhead);
- sendEnd(overhead);
- return overhead.size() + lengthOfData();
- }
-
- /**
- * Return a string representation of this object.
- * @return A string representation of this object.
- * @see java.lang.Object#toString()
- */
- @Override
- public String toString() {
- return this.getName();
- }
-
- /**
- * Write all parts and the last boundary to the specified output stream.
- *
- * @param out The stream to write to.
- * @param parts The parts to write.
- *
- * @throws IOException If an I/O error occurs while writing the parts.
- */
- public static void sendParts(OutputStream out, final Part[] parts)
- throws IOException {
- sendParts(out, parts, DEFAULT_BOUNDARY_BYTES);
- }
-
- /**
- * Write all parts and the last boundary to the specified output stream.
- *
- * @param out The stream to write to.
- * @param parts The parts to write.
- * @param partBoundary The ASCII bytes to use as the part boundary.
- *
- * @throws IOException If an I/O error occurs while writing the parts.
- *
- * @since 3.0
- */
- public static void sendParts(OutputStream out, Part[] parts, byte[] partBoundary)
- throws IOException {
-
- if (parts == null) {
- throw new IllegalArgumentException("Parts may not be null");
- }
- if (partBoundary == null || partBoundary.length == 0) {
- throw new IllegalArgumentException("partBoundary may not be empty");
- }
- for (int i = 0; i < parts.length; i++) {
- // set the part boundary before the part is sent
- parts[i].setPartBoundary(partBoundary);
- parts[i].send(out);
- }
- out.write(EXTRA_BYTES);
- out.write(partBoundary);
- out.write(EXTRA_BYTES);
- out.write(CRLF_BYTES);
- }
-
- /**
- * Return the total sum of all parts and that of the last boundary
- *
- * @param parts The parts.
- * @return The total length
- *
- * @throws IOException If an I/O error occurs while writing the parts.
- */
- public static long getLengthOfParts(Part[] parts)
- throws IOException {
- return getLengthOfParts(parts, DEFAULT_BOUNDARY_BYTES);
- }
-
- /**
- * Gets the length of the multipart message including the given parts.
- *
- * @param parts The parts.
- * @param partBoundary The ASCII bytes to use as the part boundary.
- * @return The total length
- *
- * @throws IOException If an I/O error occurs while writing the parts.
- *
- * @since 3.0
- */
- public static long getLengthOfParts(Part[] parts, byte[] partBoundary) throws IOException {
- LOG.trace("getLengthOfParts(Parts[])");
- if (parts == null) {
- throw new IllegalArgumentException("Parts may not be null");
- }
- long total = 0;
- for (int i = 0; i < parts.length; i++) {
- // set the part boundary before we calculate the part's length
- parts[i].setPartBoundary(partBoundary);
- long l = parts[i].length();
- if (l < 0) {
- return -1;
- }
- total += l;
- }
- total += EXTRA_BYTES.length;
- total += partBoundary.length;
- total += EXTRA_BYTES.length;
- total += CRLF_BYTES.length;
- return total;
- }
-}
diff --git a/core/java/com/android/internal/http/multipart/PartBase.java b/core/java/com/android/internal/http/multipart/PartBase.java
deleted file mode 100644
index 876d15d..0000000
--- a/core/java/com/android/internal/http/multipart/PartBase.java
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//httpclient/src/java/org/apache/commons/httpclient/methods/multipart/PartBase.java,v 1.5 2004/04/18 23:51:37 jsdever Exp $
- * $Revision: 480424 $
- * $Date: 2006-11-29 06:56:49 +0100 (Wed, 29 Nov 2006) $
- *
- * ====================================================================
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- * ====================================================================
- *
- * This software consists of voluntary contributions made by many
- * individuals on behalf of the Apache Software Foundation. For more
- * information on the Apache Software Foundation, please see
- * <http://www.apache.org/>.
- *
- */
-
-package com.android.internal.http.multipart;
-
-
-/**
- * Provides setters and getters for the basic Part properties.
- *
- * @author Michael Becke
- */
-public abstract class PartBase extends Part {
-
- /** Name of the file part. */
- private String name;
-
- /** Content type of the file part. */
- private String contentType;
-
- /** Content encoding of the file part. */
- private String charSet;
-
- /** The transfer encoding. */
- private String transferEncoding;
-
- /**
- * Constructor.
- *
- * @param name The name of the part
- * @param contentType The content type, or <code>null</code>
- * @param charSet The character encoding, or <code>null</code>
- * @param transferEncoding The transfer encoding, or <code>null</code>
- */
- public PartBase(String name, String contentType, String charSet, String transferEncoding) {
-
- if (name == null) {
- throw new IllegalArgumentException("Name must not be null");
- }
- this.name = name;
- this.contentType = contentType;
- this.charSet = charSet;
- this.transferEncoding = transferEncoding;
- }
-
- /**
- * Returns the name.
- * @return The name.
- * @see Part#getName()
- */
- @Override
- public String getName() {
- return this.name;
- }
-
- /**
- * Returns the content type of this part.
- * @return String The name.
- */
- @Override
- public String getContentType() {
- return this.contentType;
- }
-
- /**
- * Return the character encoding of this part.
- * @return String The name.
- */
- @Override
- public String getCharSet() {
- return this.charSet;
- }
-
- /**
- * Returns the transfer encoding of this part.
- * @return String The name.
- */
- @Override
- public String getTransferEncoding() {
- return transferEncoding;
- }
-
- /**
- * Sets the character encoding.
- *
- * @param charSet the character encoding, or <code>null</code> to exclude the character
- * encoding header
- */
- public void setCharSet(String charSet) {
- this.charSet = charSet;
- }
-
- /**
- * Sets the content type.
- *
- * @param contentType the content type, or <code>null</code> to exclude the content type header
- */
- public void setContentType(String contentType) {
- this.contentType = contentType;
- }
-
- /**
- * Sets the part name.
- *
- * @param name
- */
- public void setName(String name) {
- if (name == null) {
- throw new IllegalArgumentException("Name must not be null");
- }
- this.name = name;
- }
-
- /**
- * Sets the transfer encoding.
- *
- * @param transferEncoding the transfer encoding, or <code>null</code> to exclude the
- * transfer encoding header
- */
- public void setTransferEncoding(String transferEncoding) {
- this.transferEncoding = transferEncoding;
- }
-
-}
diff --git a/core/java/com/android/internal/http/multipart/PartSource.java b/core/java/com/android/internal/http/multipart/PartSource.java
deleted file mode 100644
index 3740696..0000000
--- a/core/java/com/android/internal/http/multipart/PartSource.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//httpclient/src/java/org/apache/commons/httpclient/methods/multipart/PartSource.java,v 1.6 2004/04/18 23:51:37 jsdever Exp $
- * $Revision: 480424 $
- * $Date: 2006-11-29 06:56:49 +0100 (Wed, 29 Nov 2006) $
- *
- * ====================================================================
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- * ====================================================================
- *
- * This software consists of voluntary contributions made by many
- * individuals on behalf of the Apache Software Foundation. For more
- * information on the Apache Software Foundation, please see
- * <http://www.apache.org/>.
- *
- */
-
-package com.android.internal.http.multipart;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-/**
- * An interface for providing access to data when posting MultiPart messages.
- *
- * @see FilePart
- *
- * @author <a href="mailto:becke@u.washington.edu">Michael Becke</a>
- *
- * @since 2.0
- */
-public interface PartSource {
-
- /**
- * Gets the number of bytes contained in this source.
- *
- * @return a value >= 0
- */
- long getLength();
-
- /**
- * Gets the name of the file this source represents.
- *
- * @return the fileName used for posting a MultiPart file part
- */
- String getFileName();
-
- /**
- * Gets a new InputStream for reading this source. This method can be
- * called more than once and should therefore return a new stream every
- * time.
- *
- * @return a new InputStream
- *
- * @throws IOException if an error occurs when creating the InputStream
- */
- InputStream createInputStream() throws IOException;
-
-}
diff --git a/core/java/com/android/internal/http/multipart/StringPart.java b/core/java/com/android/internal/http/multipart/StringPart.java
deleted file mode 100644
index 73d0f90..0000000
--- a/core/java/com/android/internal/http/multipart/StringPart.java
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//httpclient/src/java/org/apache/commons/httpclient/methods/multipart/StringPart.java,v 1.11 2004/04/18 23:51:37 jsdever Exp $
- * $Revision: 480424 $
- * $Date: 2006-11-29 06:56:49 +0100 (Wed, 29 Nov 2006) $
- *
- * ====================================================================
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- * ====================================================================
- *
- * This software consists of voluntary contributions made by many
- * individuals on behalf of the Apache Software Foundation. For more
- * information on the Apache Software Foundation, please see
- * <http://www.apache.org/>.
- *
- */
-
-package com.android.internal.http.multipart;
-
-import java.io.OutputStream;
-import java.io.IOException;
-
-import org.apache.http.util.EncodingUtils;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-/**
- * Simple string parameter for a multipart post
- *
- * @author <a href="mailto:mattalbright@yahoo.com">Matthew Albright</a>
- * @author <a href="mailto:jsdever@apache.org">Jeff Dever</a>
- * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
- * @author <a href="mailto:oleg@ural.ru">Oleg Kalnichevski</a>
- *
- * @since 2.0
- *
- * @deprecated Please use {@link java.net.URLConnection} and friends instead.
- * The Apache HTTP client is no longer maintained and may be removed in a future
- * release. Please visit <a href="http://android-developers.blogspot.com/2011/09/androids-http-clients.html">this webpage</a>
- * for further details.
- */
-@Deprecated
-public class StringPart extends PartBase {
-
- /** Log object for this class. */
- private static final Log LOG = LogFactory.getLog(StringPart.class);
-
- /** Default content encoding of string parameters. */
- public static final String DEFAULT_CONTENT_TYPE = "text/plain";
-
- /** Default charset of string parameters*/
- public static final String DEFAULT_CHARSET = "US-ASCII";
-
- /** Default transfer encoding of string parameters*/
- public static final String DEFAULT_TRANSFER_ENCODING = "8bit";
-
- /** Contents of this StringPart. */
- private byte[] content;
-
- /** The String value of this part. */
- private String value;
-
- /**
- * Constructor.
- *
- * @param name The name of the part
- * @param value the string to post
- * @param charset the charset to be used to encode the string, if <code>null</code>
- * the {@link #DEFAULT_CHARSET default} is used
- */
- public StringPart(String name, String value, String charset) {
-
- super(
- name,
- DEFAULT_CONTENT_TYPE,
- charset == null ? DEFAULT_CHARSET : charset,
- DEFAULT_TRANSFER_ENCODING
- );
- if (value == null) {
- throw new IllegalArgumentException("Value may not be null");
- }
- if (value.indexOf(0) != -1) {
- // See RFC 2048, 2.8. "8bit Data"
- throw new IllegalArgumentException("NULs may not be present in string parts");
- }
- this.value = value;
- }
-
- /**
- * Constructor.
- *
- * @param name The name of the part
- * @param value the string to post
- */
- public StringPart(String name, String value) {
- this(name, value, null);
- }
-
- /**
- * Gets the content in bytes. Bytes are lazily created to allow the charset to be changed
- * after the part is created.
- *
- * @return the content in bytes
- */
- private byte[] getContent() {
- if (content == null) {
- content = EncodingUtils.getBytes(value, getCharSet());
- }
- return content;
- }
-
- /**
- * Writes the data to the given OutputStream.
- * @param out the OutputStream to write to
- * @throws IOException if there is a write error
- */
- @Override
- protected void sendData(OutputStream out) throws IOException {
- LOG.trace("enter sendData(OutputStream)");
- out.write(getContent());
- }
-
- /**
- * Return the length of the data.
- * @return The length of the data.
- * @see Part#lengthOfData()
- */
- @Override
- protected long lengthOfData() {
- LOG.trace("enter lengthOfData()");
- return getContent().length;
- }
-
- /* (non-Javadoc)
- * @see org.apache.commons.httpclient.methods.multipart.BasePart#setCharSet(java.lang.String)
- */
- @Override
- public void setCharSet(String charSet) {
- super.setCharSet(charSet);
- this.content = null;
- }
-
-}
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 8107985..2477d94 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -355,7 +355,7 @@ public class ZygoteInit {
Log.v(TAG, "Preloading resource #" + Integer.toHexString(id));
}
if (id != 0) {
- if (mResources.getColorStateList(id) == null) {
+ if (mResources.getColorStateList(id, null) == null) {
throw new IllegalArgumentException(
"Unable to find preloaded color resource #0x"
+ Integer.toHexString(id)
diff --git a/core/java/com/android/internal/widget/ButtonBarLayout.java b/core/java/com/android/internal/widget/ButtonBarLayout.java
new file mode 100644
index 0000000..64e6c69
--- /dev/null
+++ b/core/java/com/android/internal/widget/ButtonBarLayout.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.widget;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.Gravity;
+import android.view.View;
+import android.widget.LinearLayout;
+
+import com.android.internal.R;
+
+/**
+ * An extension of LinearLayout that automatically switches to vertical
+ * orientation when it can't fit its child views horizontally.
+ */
+public class ButtonBarLayout extends LinearLayout {
+ /** Spacer used in horizontal orientation. */
+ private final View mSpacer;
+
+ /** Whether the current configuration allows stacking. */
+ private final boolean mAllowStacked;
+
+ /** Whether the layout is currently stacked. */
+ private boolean mStacked;
+
+ public ButtonBarLayout(Context context, AttributeSet attrs) {
+ super(context, attrs);
+
+ mAllowStacked = context.getResources().getBoolean(R.bool.allow_stacked_button_bar);
+ mSpacer = findViewById(R.id.spacer);
+ }
+
+ @Override
+ protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+ super.onSizeChanged(w, h, oldw, oldh);
+
+ // Maybe we can fit the content now?
+ if (w > oldw && mStacked) {
+ setStacked(false);
+ }
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+
+ if (mAllowStacked && getOrientation() == LinearLayout.HORIZONTAL) {
+ final int measuredWidth = getMeasuredWidthAndState();
+ final int measuredWidthState = measuredWidth & MEASURED_STATE_MASK;
+ if (measuredWidthState == MEASURED_STATE_TOO_SMALL) {
+ setStacked(true);
+
+ // Measure again in the new orientation.
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ }
+ }
+ }
+
+ private void setStacked(boolean stacked) {
+ setOrientation(stacked ? LinearLayout.VERTICAL : LinearLayout.HORIZONTAL);
+ setGravity(stacked ? Gravity.RIGHT : Gravity.BOTTOM);
+
+ if (mSpacer != null) {
+ mSpacer.setVisibility(stacked ? View.GONE : View.INVISIBLE);
+ }
+
+ // Reverse the child order. This is specific to the Material button
+ // bar's layout XML and will probably not generalize.
+ final int childCount = getChildCount();
+ for (int i = childCount - 2; i >= 0; i--) {
+ bringChildToFront(getChildAt(i));
+ }
+
+ mStacked = stacked;
+ }
+}
diff --git a/core/java/org/apache/http/conn/ConnectTimeoutException.java b/core/java/org/apache/http/conn/ConnectTimeoutException.java
new file mode 100644
index 0000000..6cc6922
--- /dev/null
+++ b/core/java/org/apache/http/conn/ConnectTimeoutException.java
@@ -0,0 +1,69 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/ConnectTimeoutException.java $
+ * $Revision: 617645 $
+ * $Date: 2008-02-01 13:05:31 -0800 (Fri, 01 Feb 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.conn;
+
+import java.io.InterruptedIOException;
+
+/**
+ * A timeout while connecting to an HTTP server or waiting for an
+ * available connection from an HttpConnectionManager.
+ *
+ * @author <a href="mailto:laura@lwerner.org">Laura Werner</a>
+ *
+ * @since 4.0
+ *
+ * @deprecated Please use {@link java.net.URL#openConnection} instead.
+ * Please visit <a href="http://android-developers.blogspot.com/2011/09/androids-http-clients.html">this webpage</a>
+ * for further details.
+ */
+@Deprecated
+public class ConnectTimeoutException extends InterruptedIOException {
+
+ private static final long serialVersionUID = -4816682903149535989L;
+
+ /**
+ * Creates a ConnectTimeoutException with a <tt>null</tt> detail message.
+ */
+ public ConnectTimeoutException() {
+ super();
+ }
+
+ /**
+ * Creates a ConnectTimeoutException with the specified detail message.
+ *
+ * @param message The exception detail message
+ */
+ public ConnectTimeoutException(final String message) {
+ super(message);
+ }
+
+}
diff --git a/core/java/org/apache/http/conn/scheme/HostNameResolver.java b/core/java/org/apache/http/conn/scheme/HostNameResolver.java
new file mode 100644
index 0000000..30ef298
--- /dev/null
+++ b/core/java/org/apache/http/conn/scheme/HostNameResolver.java
@@ -0,0 +1,47 @@
+/*
+ * $HeadURL:$
+ * $Revision:$
+ * $Date:$
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.conn.scheme;
+
+import java.io.IOException;
+import java.net.InetAddress;
+
+/**
+ * @deprecated Please use {@link java.net.URL#openConnection} instead.
+ * Please visit <a href="http://android-developers.blogspot.com/2011/09/androids-http-clients.html">this webpage</a>
+ * for further details.
+ */
+@Deprecated
+public interface HostNameResolver {
+
+ InetAddress resolve (String hostname) throws IOException;
+
+}
diff --git a/core/java/org/apache/http/conn/scheme/LayeredSocketFactory.java b/core/java/org/apache/http/conn/scheme/LayeredSocketFactory.java
new file mode 100644
index 0000000..b9f5348
--- /dev/null
+++ b/core/java/org/apache/http/conn/scheme/LayeredSocketFactory.java
@@ -0,0 +1,77 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/scheme/LayeredSocketFactory.java $
+ * $Revision: 645850 $
+ * $Date: 2008-04-08 04:08:52 -0700 (Tue, 08 Apr 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.conn.scheme;
+
+import java.io.IOException;
+import java.net.Socket;
+import java.net.UnknownHostException;
+
+/**
+ * A {@link SocketFactory SocketFactory} for layered sockets (SSL/TLS).
+ * See there for things to consider when implementing a socket factory.
+ *
+ * @author Michael Becke
+ * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
+ * @since 4.0
+ *
+ * @deprecated Please use {@link java.net.URL#openConnection} instead.
+ * Please visit <a href="http://android-developers.blogspot.com/2011/09/androids-http-clients.html">this webpage</a>
+ * for further details.
+ */
+@Deprecated
+public interface LayeredSocketFactory extends SocketFactory {
+
+ /**
+ * Returns a socket connected to the given host that is layered over an
+ * existing socket. Used primarily for creating secure sockets through
+ * proxies.
+ *
+ * @param socket the existing socket
+ * @param host the host name/IP
+ * @param port the port on the host
+ * @param autoClose a flag for closing the underling socket when the created
+ * socket is closed
+ *
+ * @return Socket a new socket
+ *
+ * @throws IOException if an I/O error occurs while creating the socket
+ * @throws UnknownHostException if the IP address of the host cannot be
+ * determined
+ */
+ Socket createSocket(
+ Socket socket,
+ String host,
+ int port,
+ boolean autoClose
+ ) throws IOException, UnknownHostException;
+
+}
diff --git a/core/java/org/apache/http/conn/scheme/SocketFactory.java b/core/java/org/apache/http/conn/scheme/SocketFactory.java
new file mode 100644
index 0000000..c6bc03c
--- /dev/null
+++ b/core/java/org/apache/http/conn/scheme/SocketFactory.java
@@ -0,0 +1,143 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/scheme/SocketFactory.java $
+ * $Revision: 645850 $
+ * $Date: 2008-04-08 04:08:52 -0700 (Tue, 08 Apr 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.conn.scheme;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.net.UnknownHostException;
+
+import org.apache.http.conn.ConnectTimeoutException;
+import org.apache.http.params.HttpParams;
+
+/**
+ * A factory for creating and connecting sockets.
+ * The factory encapsulates the logic for establishing a socket connection.
+ * <br/>
+ * Both {@link java.lang.Object#equals(java.lang.Object) Object.equals()}
+ * and {@link java.lang.Object#hashCode() Object.hashCode()}
+ * must be overridden for the correct operation of some connection managers.
+ *
+ * @author <a href="mailto:rolandw at apache.org">Roland Weber</a>
+ * @author Michael Becke
+ * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
+ *
+ * @deprecated Please use {@link java.net.URL#openConnection} instead.
+ * Please visit <a href="http://android-developers.blogspot.com/2011/09/androids-http-clients.html">this webpage</a>
+ * for further details.
+ */
+@Deprecated
+public interface SocketFactory {
+
+ /**
+ * Creates a new, unconnected socket.
+ * The socket should subsequently be passed to
+ * {@link #connectSocket connectSocket}.
+ *
+ * @return a new socket
+ *
+ * @throws IOException if an I/O error occurs while creating the socket
+ */
+ Socket createSocket()
+ throws IOException
+ ;
+
+
+ /**
+ * Connects a socket to the given host.
+ *
+ * @param sock the socket to connect, as obtained from
+ * {@link #createSocket createSocket}.
+ * <code>null</code> indicates that a new socket
+ * should be created and connected.
+ * @param host the host to connect to
+ * @param port the port to connect to on the host
+ * @param localAddress the local address to bind the socket to, or
+ * <code>null</code> for any
+ * @param localPort the port on the local machine,
+ * 0 or a negative number for any
+ * @param params additional {@link HttpParams parameters} for connecting
+ *
+ * @return the connected socket. The returned object may be different
+ * from the <code>sock</code> argument if this factory supports
+ * a layered protocol.
+ *
+ * @throws IOException if an I/O error occurs
+ * @throws UnknownHostException if the IP address of the target host
+ * can not be determined
+ * @throws ConnectTimeoutException if the socket cannot be connected
+ * within the time limit defined in the <code>params</code>
+ */
+ Socket connectSocket(
+ Socket sock,
+ String host,
+ int port,
+ InetAddress localAddress,
+ int localPort,
+ HttpParams params
+ ) throws IOException, UnknownHostException, ConnectTimeoutException;
+
+
+ /**
+ * Checks whether a socket provides a secure connection.
+ * The socket must be {@link #connectSocket connected}
+ * by this factory.
+ * The factory will <i>not</i> perform I/O operations
+ * in this method.
+ * <br/>
+ * As a rule of thumb, plain sockets are not secure and
+ * TLS/SSL sockets are secure. However, there may be
+ * application specific deviations. For example, a plain
+ * socket to a host in the same intranet ("trusted zone")
+ * could be considered secure. On the other hand, a
+ * TLS/SSL socket could be considered insecure based on
+ * the cypher suite chosen for the connection.
+ *
+ * @param sock the connected socket to check
+ *
+ * @return <code>true</code> if the connection of the socket
+ * should be considered secure, or
+ * <code>false</code> if it should not
+ *
+ * @throws IllegalArgumentException
+ * if the argument is invalid, for example because it is
+ * not a connected socket or was created by a different
+ * socket factory.
+ * Note that socket factories are <i>not</i> required to
+ * check these conditions, they may simply return a default
+ * value when called with an invalid socket argument.
+ */
+ boolean isSecure(Socket sock)
+ throws IllegalArgumentException
+ ;
+
+}
diff --git a/core/java/org/apache/http/conn/ssl/AbstractVerifier.java b/core/java/org/apache/http/conn/ssl/AbstractVerifier.java
new file mode 100644
index 0000000..e264f1c
--- /dev/null
+++ b/core/java/org/apache/http/conn/ssl/AbstractVerifier.java
@@ -0,0 +1,288 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/ssl/AbstractVerifier.java $
+ * $Revision: 653041 $
+ * $Date: 2008-05-03 03:39:28 -0700 (Sat, 03 May 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.conn.ssl;
+
+import java.util.regex.Pattern;
+
+import java.io.IOException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509Certificate;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Locale;
+import java.util.logging.Logger;
+import java.util.logging.Level;
+
+import javax.net.ssl.DistinguishedNameParser;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocket;
+
+/**
+ * Abstract base class for all standard {@link X509HostnameVerifier}
+ * implementations.
+ *
+ * @author Julius Davies
+ *
+ * @deprecated Please use {@link java.net.URL#openConnection} instead.
+ * Please visit <a href="http://android-developers.blogspot.com/2011/09/androids-http-clients.html">this webpage</a>
+ * for further details.
+ */
+@Deprecated
+public abstract class AbstractVerifier implements X509HostnameVerifier {
+
+ private static final Pattern IPV4_PATTERN = Pattern.compile(
+ "^(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)(\\.(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)){3}$");
+
+ /**
+ * This contains a list of 2nd-level domains that aren't allowed to
+ * have wildcards when combined with country-codes.
+ * For example: [*.co.uk].
+ * <p/>
+ * The [*.co.uk] problem is an interesting one. Should we just hope
+ * that CA's would never foolishly allow such a certificate to happen?
+ * Looks like we're the only implementation guarding against this.
+ * Firefox, Curl, Sun Java 1.4, 5, 6 don't bother with this check.
+ */
+ private final static String[] BAD_COUNTRY_2LDS =
+ { "ac", "co", "com", "ed", "edu", "go", "gouv", "gov", "info",
+ "lg", "ne", "net", "or", "org" };
+
+ static {
+ // Just in case developer forgot to manually sort the array. :-)
+ Arrays.sort(BAD_COUNTRY_2LDS);
+ }
+
+ public AbstractVerifier() {
+ super();
+ }
+
+ public final void verify(String host, SSLSocket ssl)
+ throws IOException {
+ if(host == null) {
+ throw new NullPointerException("host to verify is null");
+ }
+
+ SSLSession session = ssl.getSession();
+ Certificate[] certs = session.getPeerCertificates();
+ X509Certificate x509 = (X509Certificate) certs[0];
+ verify(host, x509);
+ }
+
+ public final boolean verify(String host, SSLSession session) {
+ try {
+ Certificate[] certs = session.getPeerCertificates();
+ X509Certificate x509 = (X509Certificate) certs[0];
+ verify(host, x509);
+ return true;
+ }
+ catch(SSLException e) {
+ return false;
+ }
+ }
+
+ public final void verify(String host, X509Certificate cert)
+ throws SSLException {
+ String[] cns = getCNs(cert);
+ String[] subjectAlts = getDNSSubjectAlts(cert);
+ verify(host, cns, subjectAlts);
+ }
+
+ public final void verify(final String host, final String[] cns,
+ final String[] subjectAlts,
+ final boolean strictWithSubDomains)
+ throws SSLException {
+
+ // Build the list of names we're going to check. Our DEFAULT and
+ // STRICT implementations of the HostnameVerifier only use the
+ // first CN provided. All other CNs are ignored.
+ // (Firefox, wget, curl, Sun Java 1.4, 5, 6 all work this way).
+ LinkedList<String> names = new LinkedList<String>();
+ if(cns != null && cns.length > 0 && cns[0] != null) {
+ names.add(cns[0]);
+ }
+ if(subjectAlts != null) {
+ for (String subjectAlt : subjectAlts) {
+ if (subjectAlt != null) {
+ names.add(subjectAlt);
+ }
+ }
+ }
+
+ if(names.isEmpty()) {
+ String msg = "Certificate for <" + host + "> doesn't contain CN or DNS subjectAlt";
+ throw new SSLException(msg);
+ }
+
+ // StringBuffer for building the error message.
+ StringBuffer buf = new StringBuffer();
+
+ // We're can be case-insensitive when comparing the host we used to
+ // establish the socket to the hostname in the certificate.
+ String hostName = host.trim().toLowerCase(Locale.ENGLISH);
+ boolean match = false;
+ for(Iterator<String> it = names.iterator(); it.hasNext();) {
+ // Don't trim the CN, though!
+ String cn = it.next();
+ cn = cn.toLowerCase(Locale.ENGLISH);
+ // Store CN in StringBuffer in case we need to report an error.
+ buf.append(" <");
+ buf.append(cn);
+ buf.append('>');
+ if(it.hasNext()) {
+ buf.append(" OR");
+ }
+
+ // The CN better have at least two dots if it wants wildcard
+ // action. It also can't be [*.co.uk] or [*.co.jp] or
+ // [*.org.uk], etc...
+ boolean doWildcard = cn.startsWith("*.") &&
+ cn.indexOf('.', 2) != -1 &&
+ acceptableCountryWildcard(cn) &&
+ !isIPv4Address(host);
+
+ if(doWildcard) {
+ match = hostName.endsWith(cn.substring(1));
+ if(match && strictWithSubDomains) {
+ // If we're in strict mode, then [*.foo.com] is not
+ // allowed to match [a.b.foo.com]
+ match = countDots(hostName) == countDots(cn);
+ }
+ } else {
+ match = hostName.equals(cn);
+ }
+ if(match) {
+ break;
+ }
+ }
+ if(!match) {
+ throw new SSLException("hostname in certificate didn't match: <" + host + "> !=" + buf);
+ }
+ }
+
+ public static boolean acceptableCountryWildcard(String cn) {
+ int cnLen = cn.length();
+ if(cnLen >= 7 && cnLen <= 9) {
+ // Look for the '.' in the 3rd-last position:
+ if(cn.charAt(cnLen - 3) == '.') {
+ // Trim off the [*.] and the [.XX].
+ String s = cn.substring(2, cnLen - 3);
+ // And test against the sorted array of bad 2lds:
+ int x = Arrays.binarySearch(BAD_COUNTRY_2LDS, s);
+ return x < 0;
+ }
+ }
+ return true;
+ }
+
+ public static String[] getCNs(X509Certificate cert) {
+ DistinguishedNameParser dnParser =
+ new DistinguishedNameParser(cert.getSubjectX500Principal());
+ List<String> cnList = dnParser.getAllMostSpecificFirst("cn");
+
+ if(!cnList.isEmpty()) {
+ String[] cns = new String[cnList.size()];
+ cnList.toArray(cns);
+ return cns;
+ } else {
+ return null;
+ }
+ }
+
+
+ /**
+ * Extracts the array of SubjectAlt DNS names from an X509Certificate.
+ * Returns null if there aren't any.
+ * <p/>
+ * Note: Java doesn't appear able to extract international characters
+ * from the SubjectAlts. It can only extract international characters
+ * from the CN field.
+ * <p/>
+ * (Or maybe the version of OpenSSL I'm using to test isn't storing the
+ * international characters correctly in the SubjectAlts?).
+ *
+ * @param cert X509Certificate
+ * @return Array of SubjectALT DNS names stored in the certificate.
+ */
+ public static String[] getDNSSubjectAlts(X509Certificate cert) {
+ LinkedList<String> subjectAltList = new LinkedList<String>();
+ Collection<List<?>> c = null;
+ try {
+ c = cert.getSubjectAlternativeNames();
+ }
+ catch(CertificateParsingException cpe) {
+ Logger.getLogger(AbstractVerifier.class.getName())
+ .log(Level.FINE, "Error parsing certificate.", cpe);
+ }
+ if(c != null) {
+ for (List<?> aC : c) {
+ List<?> list = aC;
+ int type = ((Integer) list.get(0)).intValue();
+ // If type is 2, then we've got a dNSName
+ if (type == 2) {
+ String s = (String) list.get(1);
+ subjectAltList.add(s);
+ }
+ }
+ }
+ if(!subjectAltList.isEmpty()) {
+ String[] subjectAlts = new String[subjectAltList.size()];
+ subjectAltList.toArray(subjectAlts);
+ return subjectAlts;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Counts the number of dots "." in a string.
+ * @param s string to count dots from
+ * @return number of dots
+ */
+ public static int countDots(final String s) {
+ int count = 0;
+ for(int i = 0; i < s.length(); i++) {
+ if(s.charAt(i) == '.') {
+ count++;
+ }
+ }
+ return count;
+ }
+
+ private static boolean isIPv4Address(final String input) {
+ return IPV4_PATTERN.matcher(input).matches();
+ }
+}
diff --git a/core/java/org/apache/http/conn/ssl/AllowAllHostnameVerifier.java b/core/java/org/apache/http/conn/ssl/AllowAllHostnameVerifier.java
new file mode 100644
index 0000000..c2bf4c4
--- /dev/null
+++ b/core/java/org/apache/http/conn/ssl/AllowAllHostnameVerifier.java
@@ -0,0 +1,59 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/ssl/AllowAllHostnameVerifier.java $
+ * $Revision: 617642 $
+ * $Date: 2008-02-01 12:54:07 -0800 (Fri, 01 Feb 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.conn.ssl;
+
+/**
+ * The ALLOW_ALL HostnameVerifier essentially turns hostname verification
+ * off. This implementation is a no-op, and never throws the SSLException.
+ *
+ * @author Julius Davies
+ *
+ * @deprecated Please use {@link java.net.URL#openConnection} instead.
+ * Please visit <a href="http://android-developers.blogspot.com/2011/09/androids-http-clients.html">this webpage</a>
+ * for further details.
+ */
+@Deprecated
+public class AllowAllHostnameVerifier extends AbstractVerifier {
+
+ public final void verify(
+ final String host,
+ final String[] cns,
+ final String[] subjectAlts) {
+ // Allow everything - so never blowup.
+ }
+
+ @Override
+ public final String toString() {
+ return "ALLOW_ALL";
+ }
+
+}
diff --git a/core/java/org/apache/http/conn/ssl/BrowserCompatHostnameVerifier.java b/core/java/org/apache/http/conn/ssl/BrowserCompatHostnameVerifier.java
new file mode 100644
index 0000000..48a7bf9
--- /dev/null
+++ b/core/java/org/apache/http/conn/ssl/BrowserCompatHostnameVerifier.java
@@ -0,0 +1,67 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/ssl/BrowserCompatHostnameVerifier.java $
+ * $Revision: 617642 $
+ * $Date: 2008-02-01 12:54:07 -0800 (Fri, 01 Feb 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.conn.ssl;
+
+import javax.net.ssl.SSLException;
+
+/**
+ * The HostnameVerifier that works the same way as Curl and Firefox.
+ * <p/>
+ * The hostname must match either the first CN, or any of the subject-alts.
+ * A wildcard can occur in the CN, and in any of the subject-alts.
+ * <p/>
+ * The only difference between BROWSER_COMPATIBLE and STRICT is that a wildcard
+ * (such as "*.foo.com") with BROWSER_COMPATIBLE matches all subdomains,
+ * including "a.b.foo.com".
+ *
+ * @author Julius Davies
+ *
+ * @deprecated Please use {@link java.net.URL#openConnection} instead.
+ * Please visit <a href="http://android-developers.blogspot.com/2011/09/androids-http-clients.html">this webpage</a>
+ * for further details.
+ */
+@Deprecated
+public class BrowserCompatHostnameVerifier extends AbstractVerifier {
+
+ public final void verify(
+ final String host,
+ final String[] cns,
+ final String[] subjectAlts) throws SSLException {
+ verify(host, cns, subjectAlts, false);
+ }
+
+ @Override
+ public final String toString() {
+ return "BROWSER_COMPATIBLE";
+ }
+
+}
diff --git a/core/java/org/apache/http/conn/ssl/SSLSocketFactory.java b/core/java/org/apache/http/conn/ssl/SSLSocketFactory.java
new file mode 100644
index 0000000..4d53d40
--- /dev/null
+++ b/core/java/org/apache/http/conn/ssl/SSLSocketFactory.java
@@ -0,0 +1,408 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/ssl/SSLSocketFactory.java $
+ * $Revision: 659194 $
+ * $Date: 2008-05-22 11:33:47 -0700 (Thu, 22 May 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.conn.ssl;
+
+import org.apache.http.conn.scheme.HostNameResolver;
+import org.apache.http.conn.scheme.LayeredSocketFactory;
+import org.apache.http.params.HttpConnectionParams;
+import org.apache.http.params.HttpParams;
+
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.net.UnknownHostException;
+import java.security.KeyManagementException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.security.UnrecoverableKeyException;
+
+/**
+ * Layered socket factory for TLS/SSL connections, based on JSSE.
+ *.
+ * <p>
+ * SSLSocketFactory can be used to validate the identity of the HTTPS
+ * server against a list of trusted certificates and to authenticate to
+ * the HTTPS server using a private key.
+ * </p>
+ *
+ * <p>
+ * SSLSocketFactory will enable server authentication when supplied with
+ * a {@link KeyStore truststore} file containg one or several trusted
+ * certificates. The client secure socket will reject the connection during
+ * the SSL session handshake if the target HTTPS server attempts to
+ * authenticate itself with a non-trusted certificate.
+ * </p>
+ *
+ * <p>
+ * Use JDK keytool utility to import a trusted certificate and generate a truststore file:
+ * <pre>
+ * keytool -import -alias "my server cert" -file server.crt -keystore my.truststore
+ * </pre>
+ * </p>
+ *
+ * <p>
+ * SSLSocketFactory will enable client authentication when supplied with
+ * a {@link KeyStore keystore} file containg a private key/public certificate
+ * pair. The client secure socket will use the private key to authenticate
+ * itself to the target HTTPS server during the SSL session handshake if
+ * requested to do so by the server.
+ * The target HTTPS server will in its turn verify the certificate presented
+ * by the client in order to establish client's authenticity
+ * </p>
+ *
+ * <p>
+ * Use the following sequence of actions to generate a keystore file
+ * </p>
+ * <ul>
+ * <li>
+ * <p>
+ * Use JDK keytool utility to generate a new key
+ * <pre>keytool -genkey -v -alias "my client key" -validity 365 -keystore my.keystore</pre>
+ * For simplicity use the same password for the key as that of the keystore
+ * </p>
+ * </li>
+ * <li>
+ * <p>
+ * Issue a certificate signing request (CSR)
+ * <pre>keytool -certreq -alias "my client key" -file mycertreq.csr -keystore my.keystore</pre>
+ * </p>
+ * </li>
+ * <li>
+ * <p>
+ * Send the certificate request to the trusted Certificate Authority for signature.
+ * One may choose to act as her own CA and sign the certificate request using a PKI
+ * tool, such as OpenSSL.
+ * </p>
+ * </li>
+ * <li>
+ * <p>
+ * Import the trusted CA root certificate
+ * <pre>keytool -import -alias "my trusted ca" -file caroot.crt -keystore my.keystore</pre>
+ * </p>
+ * </li>
+ * <li>
+ * <p>
+ * Import the PKCS#7 file containg the complete certificate chain
+ * <pre>keytool -import -alias "my client key" -file mycert.p7 -keystore my.keystore</pre>
+ * </p>
+ * </li>
+ * <li>
+ * <p>
+ * Verify the content the resultant keystore file
+ * <pre>keytool -list -v -keystore my.keystore</pre>
+ * </p>
+ * </li>
+ * </ul>
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ * @author Julius Davies
+ *
+ * @deprecated Please use {@link java.net.URL#openConnection} instead.
+ * Please visit <a href="http://android-developers.blogspot.com/2011/09/androids-http-clients.html">this webpage</a>
+ * for further details.
+ */
+@Deprecated
+public class SSLSocketFactory implements LayeredSocketFactory {
+
+ public static final String TLS = "TLS";
+ public static final String SSL = "SSL";
+ public static final String SSLV2 = "SSLv2";
+
+ public static final X509HostnameVerifier ALLOW_ALL_HOSTNAME_VERIFIER
+ = new AllowAllHostnameVerifier();
+
+ public static final X509HostnameVerifier BROWSER_COMPATIBLE_HOSTNAME_VERIFIER
+ = new BrowserCompatHostnameVerifier();
+
+ public static final X509HostnameVerifier STRICT_HOSTNAME_VERIFIER
+ = new StrictHostnameVerifier();
+
+ /*
+ * Put defaults into holder class to avoid class preloading creating an
+ * instance of the classes referenced.
+ */
+ private static class NoPreloadHolder {
+ /**
+ * The factory using the default JVM settings for secure connections.
+ */
+ private static final SSLSocketFactory DEFAULT_FACTORY = new SSLSocketFactory();
+ }
+
+ /**
+ * Gets an singleton instance of the SSLProtocolSocketFactory.
+ * @return a SSLProtocolSocketFactory
+ */
+ public static SSLSocketFactory getSocketFactory() {
+ return NoPreloadHolder.DEFAULT_FACTORY;
+ }
+
+ private final SSLContext sslcontext;
+ private final javax.net.ssl.SSLSocketFactory socketfactory;
+ private final HostNameResolver nameResolver;
+ private X509HostnameVerifier hostnameVerifier = BROWSER_COMPATIBLE_HOSTNAME_VERIFIER;
+
+ public SSLSocketFactory(
+ String algorithm,
+ final KeyStore keystore,
+ final String keystorePassword,
+ final KeyStore truststore,
+ final SecureRandom random,
+ final HostNameResolver nameResolver)
+ throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException
+ {
+ super();
+ if (algorithm == null) {
+ algorithm = TLS;
+ }
+ KeyManager[] keymanagers = null;
+ if (keystore != null) {
+ keymanagers = createKeyManagers(keystore, keystorePassword);
+ }
+ TrustManager[] trustmanagers = null;
+ if (truststore != null) {
+ trustmanagers = createTrustManagers(truststore);
+ }
+ this.sslcontext = SSLContext.getInstance(algorithm);
+ this.sslcontext.init(keymanagers, trustmanagers, random);
+ this.socketfactory = this.sslcontext.getSocketFactory();
+ this.nameResolver = nameResolver;
+ }
+
+ public SSLSocketFactory(
+ final KeyStore keystore,
+ final String keystorePassword,
+ final KeyStore truststore)
+ throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException
+ {
+ this(TLS, keystore, keystorePassword, truststore, null, null);
+ }
+
+ public SSLSocketFactory(final KeyStore keystore, final String keystorePassword)
+ throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException
+ {
+ this(TLS, keystore, keystorePassword, null, null, null);
+ }
+
+ public SSLSocketFactory(final KeyStore truststore)
+ throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException
+ {
+ this(TLS, null, null, truststore, null, null);
+ }
+
+ /**
+ * Constructs an HttpClient SSLSocketFactory backed by the given JSSE
+ * SSLSocketFactory.
+ *
+ * @hide
+ */
+ public SSLSocketFactory(javax.net.ssl.SSLSocketFactory socketfactory) {
+ super();
+ this.sslcontext = null;
+ this.socketfactory = socketfactory;
+ this.nameResolver = null;
+ }
+
+ /**
+ * Creates the default SSL socket factory.
+ * This constructor is used exclusively to instantiate the factory for
+ * {@link #getSocketFactory getSocketFactory}.
+ */
+ private SSLSocketFactory() {
+ super();
+ this.sslcontext = null;
+ this.socketfactory = HttpsURLConnection.getDefaultSSLSocketFactory();
+ this.nameResolver = null;
+ }
+
+ private static KeyManager[] createKeyManagers(final KeyStore keystore, final String password)
+ throws KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException {
+ if (keystore == null) {
+ throw new IllegalArgumentException("Keystore may not be null");
+ }
+ KeyManagerFactory kmfactory = KeyManagerFactory.getInstance(
+ KeyManagerFactory.getDefaultAlgorithm());
+ kmfactory.init(keystore, password != null ? password.toCharArray(): null);
+ return kmfactory.getKeyManagers();
+ }
+
+ private static TrustManager[] createTrustManagers(final KeyStore keystore)
+ throws KeyStoreException, NoSuchAlgorithmException {
+ if (keystore == null) {
+ throw new IllegalArgumentException("Keystore may not be null");
+ }
+ TrustManagerFactory tmfactory = TrustManagerFactory.getInstance(
+ TrustManagerFactory.getDefaultAlgorithm());
+ tmfactory.init(keystore);
+ return tmfactory.getTrustManagers();
+ }
+
+
+ // non-javadoc, see interface org.apache.http.conn.SocketFactory
+ public Socket createSocket()
+ throws IOException {
+
+ // the cast makes sure that the factory is working as expected
+ return (SSLSocket) this.socketfactory.createSocket();
+ }
+
+
+ // non-javadoc, see interface org.apache.http.conn.SocketFactory
+ public Socket connectSocket(
+ final Socket sock,
+ final String host,
+ final int port,
+ final InetAddress localAddress,
+ int localPort,
+ final HttpParams params
+ ) throws IOException {
+
+ if (host == null) {
+ throw new IllegalArgumentException("Target host may not be null.");
+ }
+ if (params == null) {
+ throw new IllegalArgumentException("Parameters may not be null.");
+ }
+
+ SSLSocket sslsock = (SSLSocket)
+ ((sock != null) ? sock : createSocket());
+
+ if ((localAddress != null) || (localPort > 0)) {
+
+ // we need to bind explicitly
+ if (localPort < 0)
+ localPort = 0; // indicates "any"
+
+ InetSocketAddress isa =
+ new InetSocketAddress(localAddress, localPort);
+ sslsock.bind(isa);
+ }
+
+ int connTimeout = HttpConnectionParams.getConnectionTimeout(params);
+ int soTimeout = HttpConnectionParams.getSoTimeout(params);
+
+ InetSocketAddress remoteAddress;
+ if (this.nameResolver != null) {
+ remoteAddress = new InetSocketAddress(this.nameResolver.resolve(host), port);
+ } else {
+ remoteAddress = new InetSocketAddress(host, port);
+ }
+
+ sslsock.connect(remoteAddress, connTimeout);
+
+ sslsock.setSoTimeout(soTimeout);
+ try {
+ hostnameVerifier.verify(host, sslsock);
+ // verifyHostName() didn't blowup - good!
+ } catch (IOException iox) {
+ // close the socket before re-throwing the exception
+ try { sslsock.close(); } catch (Exception x) { /*ignore*/ }
+ throw iox;
+ }
+
+ return sslsock;
+ }
+
+
+ /**
+ * Checks whether a socket connection is secure.
+ * This factory creates TLS/SSL socket connections
+ * which, by default, are considered secure.
+ * <br/>
+ * Derived classes may override this method to perform
+ * runtime checks, for example based on the cypher suite.
+ *
+ * @param sock the connected socket
+ *
+ * @return <code>true</code>
+ *
+ * @throws IllegalArgumentException if the argument is invalid
+ */
+ public boolean isSecure(Socket sock)
+ throws IllegalArgumentException {
+
+ if (sock == null) {
+ throw new IllegalArgumentException("Socket may not be null.");
+ }
+ // This instanceof check is in line with createSocket() above.
+ if (!(sock instanceof SSLSocket)) {
+ throw new IllegalArgumentException
+ ("Socket not created by this factory.");
+ }
+ // This check is performed last since it calls the argument object.
+ if (sock.isClosed()) {
+ throw new IllegalArgumentException("Socket is closed.");
+ }
+
+ return true;
+
+ } // isSecure
+
+
+ // non-javadoc, see interface LayeredSocketFactory
+ public Socket createSocket(
+ final Socket socket,
+ final String host,
+ final int port,
+ final boolean autoClose
+ ) throws IOException, UnknownHostException {
+ SSLSocket sslSocket = (SSLSocket) this.socketfactory.createSocket(
+ socket,
+ host,
+ port,
+ autoClose
+ );
+ hostnameVerifier.verify(host, sslSocket);
+ // verifyHostName() didn't blowup - good!
+ return sslSocket;
+ }
+
+ public void setHostnameVerifier(X509HostnameVerifier hostnameVerifier) {
+ if ( hostnameVerifier == null ) {
+ throw new IllegalArgumentException("Hostname verifier may not be null");
+ }
+ this.hostnameVerifier = hostnameVerifier;
+ }
+
+ public X509HostnameVerifier getHostnameVerifier() {
+ return hostnameVerifier;
+ }
+
+}
diff --git a/core/java/org/apache/http/conn/ssl/StrictHostnameVerifier.java b/core/java/org/apache/http/conn/ssl/StrictHostnameVerifier.java
new file mode 100644
index 0000000..bd9e70d
--- /dev/null
+++ b/core/java/org/apache/http/conn/ssl/StrictHostnameVerifier.java
@@ -0,0 +1,74 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/ssl/StrictHostnameVerifier.java $
+ * $Revision: 617642 $
+ * $Date: 2008-02-01 12:54:07 -0800 (Fri, 01 Feb 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.conn.ssl;
+
+import javax.net.ssl.SSLException;
+
+/**
+ * The Strict HostnameVerifier works the same way as Sun Java 1.4, Sun
+ * Java 5, Sun Java 6-rc. It's also pretty close to IE6. This
+ * implementation appears to be compliant with RFC 2818 for dealing with
+ * wildcards.
+ * <p/>
+ * The hostname must match either the first CN, or any of the subject-alts.
+ * A wildcard can occur in the CN, and in any of the subject-alts. The
+ * one divergence from IE6 is how we only check the first CN. IE6 allows
+ * a match against any of the CNs present. We decided to follow in
+ * Sun Java 1.4's footsteps and only check the first CN. (If you need
+ * to check all the CN's, feel free to write your own implementation!).
+ * <p/>
+ * A wildcard such as "*.foo.com" matches only subdomains in the same
+ * level, for example "a.foo.com". It does not match deeper subdomains
+ * such as "a.b.foo.com".
+ *
+ * @author Julius Davies
+ *
+ * @deprecated Please use {@link java.net.URL#openConnection} instead.
+ * Please visit <a href="http://android-developers.blogspot.com/2011/09/androids-http-clients.html">this webpage</a>
+ * for further details.
+ */
+@Deprecated
+public class StrictHostnameVerifier extends AbstractVerifier {
+
+ public final void verify(
+ final String host,
+ final String[] cns,
+ final String[] subjectAlts) throws SSLException {
+ verify(host, cns, subjectAlts, true);
+ }
+
+ @Override
+ public final String toString() {
+ return "STRICT";
+ }
+
+}
diff --git a/core/java/org/apache/http/conn/ssl/X509HostnameVerifier.java b/core/java/org/apache/http/conn/ssl/X509HostnameVerifier.java
new file mode 100644
index 0000000..e38db5f
--- /dev/null
+++ b/core/java/org/apache/http/conn/ssl/X509HostnameVerifier.java
@@ -0,0 +1,91 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/ssl/X509HostnameVerifier.java $
+ * $Revision: 618365 $
+ * $Date: 2008-02-04 10:20:08 -0800 (Mon, 04 Feb 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.conn.ssl;
+
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocket;
+import java.io.IOException;
+import java.security.cert.X509Certificate;
+
+/**
+ * Interface for checking if a hostname matches the names stored inside the
+ * server's X.509 certificate. Implements javax.net.ssl.HostnameVerifier, but
+ * we don't actually use that interface. Instead we added some methods that
+ * take String parameters (instead of javax.net.ssl.HostnameVerifier's
+ * SSLSession). JUnit is a lot easier this way! :-)
+ * <p/>
+ * We provide the HostnameVerifier.DEFAULT, HostnameVerifier.STRICT, and
+ * HostnameVerifier.ALLOW_ALL implementations. But feel free to define
+ * your own implementation!
+ * <p/>
+ * Inspired by Sebastian Hauer's original StrictSSLProtocolSocketFactory in the
+ * HttpClient "contrib" repository.
+ *
+ * @author Julius Davies
+ * @author <a href="mailto:hauer@psicode.com">Sebastian Hauer</a>
+ *
+ * @since 4.0 (8-Dec-2006)
+ *
+ * @deprecated Please use {@link java.net.URL#openConnection} instead.
+ * Please visit <a href="http://android-developers.blogspot.com/2011/09/androids-http-clients.html">this webpage</a>
+ * for further details.
+ */
+@Deprecated
+public interface X509HostnameVerifier extends HostnameVerifier {
+
+ boolean verify(String host, SSLSession session);
+
+ void verify(String host, SSLSocket ssl) throws IOException;
+
+ void verify(String host, X509Certificate cert) throws SSLException;
+
+ /**
+ * Checks to see if the supplied hostname matches any of the supplied CNs
+ * or "DNS" Subject-Alts. Most implementations only look at the first CN,
+ * and ignore any additional CNs. Most implementations do look at all of
+ * the "DNS" Subject-Alts. The CNs or Subject-Alts may contain wildcards
+ * according to RFC 2818.
+ *
+ * @param cns CN fields, in order, as extracted from the X.509
+ * certificate.
+ * @param subjectAlts Subject-Alt fields of type 2 ("DNS"), as extracted
+ * from the X.509 certificate.
+ * @param host The hostname to verify.
+ * @throws SSLException If verification failed.
+ */
+ void verify(String host, String[] cns, String[] subjectAlts)
+ throws SSLException;
+
+
+}
diff --git a/core/java/org/apache/http/conn/ssl/package.html b/core/java/org/apache/http/conn/ssl/package.html
new file mode 100644
index 0000000..a5c737f
--- /dev/null
+++ b/core/java/org/apache/http/conn/ssl/package.html
@@ -0,0 +1,40 @@
+<html>
+<head>
+<!--
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/ssl/package.html $
+ * $Revision: 555193 $
+ * $Date: 2007-07-11 00:36:47 -0700 (Wed, 11 Jul 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+-->
+</head>
+<body>
+TLS/SSL specific parts of the <i>HttpConn</i> API.
+
+</body>
+</html>
diff --git a/core/java/org/apache/http/params/CoreConnectionPNames.java b/core/java/org/apache/http/params/CoreConnectionPNames.java
new file mode 100644
index 0000000..9479db1
--- /dev/null
+++ b/core/java/org/apache/http/params/CoreConnectionPNames.java
@@ -0,0 +1,136 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/params/CoreConnectionPNames.java $
+ * $Revision: 576077 $
+ * $Date: 2007-09-16 04:50:22 -0700 (Sun, 16 Sep 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.params;
+
+
+/**
+ * Defines parameter names for connections in HttpCore.
+ *
+ * @version $Revision: 576077 $
+ *
+ * @since 4.0
+ *
+ * @deprecated Please use {@link java.net.URL#openConnection} instead.
+ * Please visit <a href="http://android-developers.blogspot.com/2011/09/androids-http-clients.html">this webpage</a>
+ * for further details.
+ */
+@Deprecated
+public interface CoreConnectionPNames {
+
+ /**
+ * Defines the default socket timeout (<tt>SO_TIMEOUT</tt>) in milliseconds which is the
+ * timeout for waiting for data. A timeout value of zero is interpreted as an infinite
+ * timeout. This value is used when no socket timeout is set in the
+ * method parameters.
+ * <p>
+ * This parameter expects a value of type {@link Integer}.
+ * </p>
+ * @see java.net.SocketOptions#SO_TIMEOUT
+ */
+ public static final String SO_TIMEOUT = "http.socket.timeout";
+
+ /**
+ * Determines whether Nagle's algorithm is to be used. The Nagle's algorithm
+ * tries to conserve bandwidth by minimizing the number of segments that are
+ * sent. When applications wish to decrease network latency and increase
+ * performance, they can disable Nagle's algorithm (that is enable TCP_NODELAY).
+ * Data will be sent earlier, at the cost of an increase in bandwidth consumption.
+ * <p>
+ * This parameter expects a value of type {@link Boolean}.
+ * </p>
+ * @see java.net.SocketOptions#TCP_NODELAY
+ */
+ public static final String TCP_NODELAY = "http.tcp.nodelay";
+
+ /**
+ * Determines the size of the internal socket buffer used to buffer data
+ * while receiving / transmitting HTTP messages.
+ * <p>
+ * This parameter expects a value of type {@link Integer}.
+ * </p>
+ */
+ public static final String SOCKET_BUFFER_SIZE = "http.socket.buffer-size";
+
+ /**
+ * Sets SO_LINGER with the specified linger time in seconds. The maximum timeout
+ * value is platform specific. Value <tt>0</tt> implies that the option is disabled.
+ * Value <tt>-1</tt> implies that the JRE default is used. The setting only affects
+ * socket close.
+ * <p>
+ * This parameter expects a value of type {@link Integer}.
+ * </p>
+ * @see java.net.SocketOptions#SO_LINGER
+ */
+ public static final String SO_LINGER = "http.socket.linger";
+
+ /**
+ * Determines the timeout until a connection is etablished. A value of zero
+ * means the timeout is not used. The default value is zero.
+ * <p>
+ * This parameter expects a value of type {@link Integer}.
+ * </p>
+ */
+ public static final String CONNECTION_TIMEOUT = "http.connection.timeout";
+
+ /**
+ * Determines whether stale connection check is to be used. Disabling
+ * stale connection check may result in slight performance improvement
+ * at the risk of getting an I/O error when executing a request over a
+ * connection that has been closed at the server side.
+ * <p>
+ * This parameter expects a value of type {@link Boolean}.
+ * </p>
+ */
+ public static final String STALE_CONNECTION_CHECK = "http.connection.stalecheck";
+
+ /**
+ * Determines the maximum line length limit. If set to a positive value, any HTTP
+ * line exceeding this limit will cause an IOException. A negative or zero value
+ * will effectively disable the check.
+ * <p>
+ * This parameter expects a value of type {@link Integer}.
+ * </p>
+ */
+ public static final String MAX_LINE_LENGTH = "http.connection.max-line-length";
+
+ /**
+ * Determines the maximum HTTP header count allowed. If set to a positive value,
+ * the number of HTTP headers received from the data stream exceeding this limit
+ * will cause an IOException. A negative or zero value will effectively disable
+ * the check.
+ * <p>
+ * This parameter expects a value of type {@link Integer}.
+ * </p>
+ */
+ public static final String MAX_HEADER_COUNT = "http.connection.max-header-count";
+
+}
diff --git a/core/java/org/apache/http/params/HttpConnectionParams.java b/core/java/org/apache/http/params/HttpConnectionParams.java
new file mode 100644
index 0000000..a7b31fc
--- /dev/null
+++ b/core/java/org/apache/http/params/HttpConnectionParams.java
@@ -0,0 +1,229 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/params/HttpConnectionParams.java $
+ * $Revision: 576089 $
+ * $Date: 2007-09-16 05:39:56 -0700 (Sun, 16 Sep 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.params;
+
+/**
+ * An adaptor for accessing connection parameters in {@link HttpParams}.
+ * <br/>
+ * Note that the <i>implements</i> relation to {@link CoreConnectionPNames}
+ * is for compatibility with existing application code only. References to
+ * the parameter names should use the interface, not this class.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 576089 $
+ *
+ * @since 4.0
+ *
+ * @deprecated Please use {@link java.net.URL#openConnection} instead.
+ * Please visit <a href="http://android-developers.blogspot.com/2011/09/androids-http-clients.html">this webpage</a>
+ * for further details.
+ */
+@Deprecated
+public final class HttpConnectionParams implements CoreConnectionPNames {
+
+ /**
+ */
+ private HttpConnectionParams() {
+ super();
+ }
+
+ /**
+ * Returns the default socket timeout (<tt>SO_TIMEOUT</tt>) in milliseconds which is the
+ * timeout for waiting for data. A timeout value of zero is interpreted as an infinite
+ * timeout. This value is used when no socket timeout is set in the
+ * method parameters.
+ *
+ * @return timeout in milliseconds
+ */
+ public static int getSoTimeout(final HttpParams params) {
+ if (params == null) {
+ throw new IllegalArgumentException("HTTP parameters may not be null");
+ }
+ return params.getIntParameter(CoreConnectionPNames.SO_TIMEOUT, 0);
+ }
+
+ /**
+ * Sets the default socket timeout (<tt>SO_TIMEOUT</tt>) in milliseconds which is the
+ * timeout for waiting for data. A timeout value of zero is interpreted as an infinite
+ * timeout. This value is used when no socket timeout is set in the
+ * method parameters.
+ *
+ * @param timeout Timeout in milliseconds
+ */
+ public static void setSoTimeout(final HttpParams params, int timeout) {
+ if (params == null) {
+ throw new IllegalArgumentException("HTTP parameters may not be null");
+ }
+ params.setIntParameter(CoreConnectionPNames.SO_TIMEOUT, timeout);
+
+ }
+
+ /**
+ * Tests if Nagle's algorithm is to be used.
+ *
+ * @return <tt>true</tt> if the Nagle's algorithm is to NOT be used
+ * (that is enable TCP_NODELAY), <tt>false</tt> otherwise.
+ */
+ public static boolean getTcpNoDelay(final HttpParams params) {
+ if (params == null) {
+ throw new IllegalArgumentException("HTTP parameters may not be null");
+ }
+ return params.getBooleanParameter
+ (CoreConnectionPNames.TCP_NODELAY, true);
+ }
+
+ /**
+ * Determines whether Nagle's algorithm is to be used. The Nagle's algorithm
+ * tries to conserve bandwidth by minimizing the number of segments that are
+ * sent. When applications wish to decrease network latency and increase
+ * performance, they can disable Nagle's algorithm (that is enable TCP_NODELAY).
+ * Data will be sent earlier, at the cost of an increase in bandwidth consumption.
+ *
+ * @param value <tt>true</tt> if the Nagle's algorithm is to NOT be used
+ * (that is enable TCP_NODELAY), <tt>false</tt> otherwise.
+ */
+ public static void setTcpNoDelay(final HttpParams params, boolean value) {
+ if (params == null) {
+ throw new IllegalArgumentException("HTTP parameters may not be null");
+ }
+ params.setBooleanParameter(CoreConnectionPNames.TCP_NODELAY, value);
+ }
+
+ public static int getSocketBufferSize(final HttpParams params) {
+ if (params == null) {
+ throw new IllegalArgumentException("HTTP parameters may not be null");
+ }
+ return params.getIntParameter
+ (CoreConnectionPNames.SOCKET_BUFFER_SIZE, -1);
+ }
+
+ public static void setSocketBufferSize(final HttpParams params, int size) {
+ if (params == null) {
+ throw new IllegalArgumentException("HTTP parameters may not be null");
+ }
+ params.setIntParameter(CoreConnectionPNames.SOCKET_BUFFER_SIZE, size);
+ }
+
+ /**
+ * Returns linger-on-close timeout. Value <tt>0</tt> implies that the option is
+ * disabled. Value <tt>-1</tt> implies that the JRE default is used.
+ *
+ * @return the linger-on-close timeout
+ */
+ public static int getLinger(final HttpParams params) {
+ if (params == null) {
+ throw new IllegalArgumentException("HTTP parameters may not be null");
+ }
+ return params.getIntParameter(CoreConnectionPNames.SO_LINGER, -1);
+ }
+
+ /**
+ * Returns linger-on-close timeout. This option disables/enables immediate return
+ * from a close() of a TCP Socket. Enabling this option with a non-zero Integer
+ * timeout means that a close() will block pending the transmission and
+ * acknowledgement of all data written to the peer, at which point the socket is
+ * closed gracefully. Value <tt>0</tt> implies that the option is
+ * disabled. Value <tt>-1</tt> implies that the JRE default is used.
+ *
+ * @param value the linger-on-close timeout
+ */
+ public static void setLinger(final HttpParams params, int value) {
+ if (params == null) {
+ throw new IllegalArgumentException("HTTP parameters may not be null");
+ }
+ params.setIntParameter(CoreConnectionPNames.SO_LINGER, value);
+ }
+
+ /**
+ * Returns the timeout until a connection is etablished. A value of zero
+ * means the timeout is not used. The default value is zero.
+ *
+ * @return timeout in milliseconds.
+ */
+ public static int getConnectionTimeout(final HttpParams params) {
+ if (params == null) {
+ throw new IllegalArgumentException("HTTP parameters may not be null");
+ }
+ return params.getIntParameter
+ (CoreConnectionPNames.CONNECTION_TIMEOUT, 0);
+ }
+
+ /**
+ * Sets the timeout until a connection is etablished. A value of zero
+ * means the timeout is not used. The default value is zero.
+ *
+ * @param timeout Timeout in milliseconds.
+ */
+ public static void setConnectionTimeout(final HttpParams params, int timeout) {
+ if (params == null) {
+ throw new IllegalArgumentException("HTTP parameters may not be null");
+ }
+ params.setIntParameter
+ (CoreConnectionPNames.CONNECTION_TIMEOUT, timeout);
+ }
+
+ /**
+ * Tests whether stale connection check is to be used. Disabling
+ * stale connection check may result in slight performance improvement
+ * at the risk of getting an I/O error when executing a request over a
+ * connection that has been closed at the server side.
+ *
+ * @return <tt>true</tt> if stale connection check is to be used,
+ * <tt>false</tt> otherwise.
+ */
+ public static boolean isStaleCheckingEnabled(final HttpParams params) {
+ if (params == null) {
+ throw new IllegalArgumentException("HTTP parameters may not be null");
+ }
+ return params.getBooleanParameter
+ (CoreConnectionPNames.STALE_CONNECTION_CHECK, true);
+ }
+
+ /**
+ * Defines whether stale connection check is to be used. Disabling
+ * stale connection check may result in slight performance improvement
+ * at the risk of getting an I/O error when executing a request over a
+ * connection that has been closed at the server side.
+ *
+ * @param value <tt>true</tt> if stale connection check is to be used,
+ * <tt>false</tt> otherwise.
+ */
+ public static void setStaleCheckingEnabled(final HttpParams params, boolean value) {
+ if (params == null) {
+ throw new IllegalArgumentException("HTTP parameters may not be null");
+ }
+ params.setBooleanParameter
+ (CoreConnectionPNames.STALE_CONNECTION_CHECK, value);
+ }
+
+}
diff --git a/core/java/org/apache/http/params/HttpParams.java b/core/java/org/apache/http/params/HttpParams.java
new file mode 100644
index 0000000..9562e54
--- /dev/null
+++ b/core/java/org/apache/http/params/HttpParams.java
@@ -0,0 +1,192 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/params/HttpParams.java $
+ * $Revision: 610763 $
+ * $Date: 2008-01-10 04:01:13 -0800 (Thu, 10 Jan 2008) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.http.params;
+
+/**
+ * Represents a collection of HTTP protocol and framework parameters.
+ *
+ * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
+ *
+ * @version $Revision: 610763 $
+ *
+ * @since 4.0
+ *
+ * @deprecated Please use {@link java.net.URL#openConnection} instead.
+ * Please visit <a href="http://android-developers.blogspot.com/2011/09/androids-http-clients.html">this webpage</a>
+ * for further details.
+ */
+@Deprecated
+public interface HttpParams {
+
+ /**
+ * Obtains the value of the given parameter.
+ *
+ * @param name the parent name.
+ *
+ * @return an object that represents the value of the parameter,
+ * <code>null</code> if the parameter is not set or if it
+ * is explicitly set to <code>null</code>
+ *
+ * @see #setParameter(String, Object)
+ */
+ Object getParameter(String name);
+
+ /**
+ * Assigns the value to the parameter with the given name.
+ *
+ * @param name parameter name
+ * @param value parameter value
+ */
+ HttpParams setParameter(String name, Object value);
+
+ /**
+ * Creates a copy of these parameters.
+ *
+ * @return a new set of parameters holding the same values as this one
+ */
+ HttpParams copy();
+
+ /**
+ * Removes the parameter with the specified name.
+ *
+ * @param name parameter name
+ *
+ * @return true if the parameter existed and has been removed, false else.
+ */
+ boolean removeParameter(String name);
+
+ /**
+ * Returns a {@link Long} parameter value with the given name.
+ * If the parameter is not explicitly set, the default value is returned.
+ *
+ * @param name the parent name.
+ * @param defaultValue the default value.
+ *
+ * @return a {@link Long} that represents the value of the parameter.
+ *
+ * @see #setLongParameter(String, long)
+ */
+ long getLongParameter(String name, long defaultValue);
+
+ /**
+ * Assigns a {@link Long} to the parameter with the given name
+ *
+ * @param name parameter name
+ * @param value parameter value
+ */
+ HttpParams setLongParameter(String name, long value);
+
+ /**
+ * Returns an {@link Integer} parameter value with the given name.
+ * If the parameter is not explicitly set, the default value is returned.
+ *
+ * @param name the parent name.
+ * @param defaultValue the default value.
+ *
+ * @return a {@link Integer} that represents the value of the parameter.
+ *
+ * @see #setIntParameter(String, int)
+ */
+ int getIntParameter(String name, int defaultValue);
+
+ /**
+ * Assigns an {@link Integer} to the parameter with the given name
+ *
+ * @param name parameter name
+ * @param value parameter value
+ */
+ HttpParams setIntParameter(String name, int value);
+
+ /**
+ * Returns a {@link Double} parameter value with the given name.
+ * If the parameter is not explicitly set, the default value is returned.
+ *
+ * @param name the parent name.
+ * @param defaultValue the default value.
+ *
+ * @return a {@link Double} that represents the value of the parameter.
+ *
+ * @see #setDoubleParameter(String, double)
+ */
+ double getDoubleParameter(String name, double defaultValue);
+
+ /**
+ * Assigns a {@link Double} to the parameter with the given name
+ *
+ * @param name parameter name
+ * @param value parameter value
+ */
+ HttpParams setDoubleParameter(String name, double value);
+
+ /**
+ * Returns a {@link Boolean} parameter value with the given name.
+ * If the parameter is not explicitly set, the default value is returned.
+ *
+ * @param name the parent name.
+ * @param defaultValue the default value.
+ *
+ * @return a {@link Boolean} that represents the value of the parameter.
+ *
+ * @see #setBooleanParameter(String, boolean)
+ */
+ boolean getBooleanParameter(String name, boolean defaultValue);
+
+ /**
+ * Assigns a {@link Boolean} to the parameter with the given name
+ *
+ * @param name parameter name
+ * @param value parameter value
+ */
+ HttpParams setBooleanParameter(String name, boolean value);
+
+ /**
+ * Checks if a boolean parameter is set to <code>true</code>.
+ *
+ * @param name parameter name
+ *
+ * @return <tt>true</tt> if the parameter is set to value <tt>true</tt>,
+ * <tt>false</tt> if it is not set or set to <code>false</code>
+ */
+ boolean isParameterTrue(String name);
+
+ /**
+ * Checks if a boolean parameter is not set or <code>false</code>.
+ *
+ * @param name parameter name
+ *
+ * @return <tt>true</tt> if the parameter is either not set or
+ * set to value <tt>false</tt>,
+ * <tt>false</tt> if it is set to <code>true</code>
+ */
+ boolean isParameterFalse(String name);
+
+}