Android 4.0 でも動く HTTPS通信は、、、

Android 2.3.3 で動作していた javax.net.ssl.HttpsURLConnection.getServerCertificates() が、
Android 3.0~以降では、以下のような例外が発生する。

Caused by: java.lang.IllegalStateException
at libcore.net.http.HttpEngine.getCacheResponse(HttpEngine.java:412)
at libcore.net.http.HttpsURLConnectionImpl$HttpUrlConnectionDelegate.getCacheResponse(HttpsURLConnectionImpl.java:390)
at libcore.net.http.HttpsURLConnectionImpl.getServerCertificates(HttpsURLConnectionImpl.java:87)

どうやら、SSLSocketFactory の実装方法を変えないとダメらしく、Android 2.3.3 / 3.0 / 4.0 全てで動かすために
HTTPS 通信プログラムを以下のように書いたら動作した。
(結果を参照するために独自の interface を定義している)

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.concurrent.Callable;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.scheme.LayeredSocketFactory;
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.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.SingleClientConnManager;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
/**
 * HttpSslGet.  
HttpResult は、独自の結果参照インターフェース
 */

public class HttpSslGet implements Callable<HttpResult>{
   private String url;

   public HttpSslGet(String url){
      this.url = url;
   }
   @Override
   public HttpResult call() throws Exception{

      HttpClient client = new MyHttpClient();  //→ DefaultHttpClient継承 
      HttpResponse response = client.execute(new HttpGet(url));

      Result result = new Result(response.getStatusLine().getStatusCode(),response.getAllHeaders());
      if (result.getStatusCode()==HttpStatus.SC_OK){
         ByteArrayOutputStream stream = new ByteArrayOutputStream();
         response.getEntity().writeTo(stream);
         result.setBytes(stream);
         stream.close();
      }
      return result;
   }

   class MyHttpClient extends DefaultHttpClient{
      @Override
      protected ClientConnectionManager createClientConnectionManager(){
         SchemeRegistry registry = new SchemeRegistry();
         registry.register(new Scheme("http",PlainSocketFactory.getSocketFactory(),80));
         try{
         SSLContext sslcontext = SSLContext.getInstance(SSLSocketFactory.TLS);
         sslcontext.init(null,new TrustManager{ new X509TrustManager(){
            @Override
            public void checkClientTrusted(X509Certificate
 chain,String authType) throws CertificateException{
            }
            @Override
            public void checkServerTrusted(X509Certificate chain,String authType) throws CertificateException{
            }
            @Override
            public X509Certificate
 getAcceptedIssuers(){
               return new X509Certificate[0];
            }
         }}
,new SecureRandom());

         final javax.net.ssl.SSLSocketFactory socketfactory = sslcontext.getSocketFactory();

         registry.register(new Scheme("https",new LayeredSocketFactory(){
            @Override
            public Socket createSocket(Socket socket,String host,int port
,boolean autoClose) throws IOException,UnknownHostException{

               return socketfactory.createSocket(socket,host,port,autoClose);
            }
            @Override
            public Socket connectSocket(Socket sock,String host,int port,InetAddress localAddress
,int localPort,HttpParams params) throws IOException,UnknownHostException,ConnectTimeoutException{

               SSLSocket sslsock = (SSLSocket)*1;
               if (localAddress != null || localPort > 0){
                  InetSocketAddress isa = new InetSocketAddress(localAddress,localPort);
                  sslsock.bind(isa);
               }
               int connTimeout = HttpConnectionParams.getConnectionTimeout(params);
               int soTimeout = HttpConnectionParams.getSoTimeout(params);
               InetSocketAddress remoteAddress;
               remoteAddress = new InetSocketAddress(host,port);
               sslsock.connect(remoteAddress, connTimeout);
               sslsock.setSoTimeout(soTimeout);
               return sslsock;
            }
            @Override
            public Socket createSocket() throws IOException{

               return socketfactory.createSocket();
            }
            @Override
            public boolean isSecure(Socket sock) throws IllegalArgumentException{

               return true;
            }
         }
,443));
         }catch(Exception e){
            throw new RuntimeException(e);
         }
         return new SingleClientConnManager(getParams(),registry);
      }
   }
   class Result implements HttpResult{
      private int code;
      private byte bytes;
      private Header
 headers;

      protected Result(int code,Header headers){
         this.code = code;
         this.headers = headers;
      }
      @Override
      public int getStatusCode(){
         return this.code;
      }
      @Override
      public byte
 getBytes(){
         return this.bytes;
      }
      @Override
      public String getString(){
         return new String(this.bytes);
      }
      @Override
      public Header getHeaders(){
         return this.headers;
      }
      protected void setBytes(ByteArrayOutputStream stream){
         bytes = stream.toByteArray();
      }
   }
}

public interface HttpResult{

   /**
    * @return HTTP status code
    */

   public int getStatusCode();

   /**
    * @return org.apache.http.Header
    * Header#getName() と Header#getValue() で参照できる。
    */

   public Header
 getHeaders();

   /**
    * @return 取得コンテンツ
    */

   public byte[] getBytes();

   /**
    * @return 取得コンテンツ
    */

   public String getString();
}
----------------------------------------------------
使い方、、、

Future<HttpResult> future = Executors.newSingleThreadExecutor().submit(new HttpSslGet(url));
HttpResult result = future.get();

if (result.getStatusCode()==HttpStatus.SC_OK){

}

*1:sock != null) ? sock : createSocket(