I've used protocol handlers in the past overriding the default http handler and creating my own custom handlers and I was thinking the approach still works on Android. I am trying to override any http or https URL requested by my Android app and pass it to a custom handler under certain situations. However I still would like to access web resources in other cases. How do I retrieve the default http/https protocol handlers? I'm trying something like the following to load the default handler before putting my override in place:
static URLStreamHandler handler;
static {
Class<?> handlerClass;
try {
handlerClass = Class.forName("net.www.protocol.http.Handler");
} catch (ClassNotFoundException e) {
throw new RuntimeException("Error loading clas for default http handler.", e);
}
Object handlerInstance;
try {
handlerInstance = handlerClass.newInstance();
} catch (InstantiationException e) {
throw new RuntimeException("Error instantiating default http handler.", e);
} catch (IllegalAccessException e) {
throw new RuntimeException("Error accessing default http handler.", e);
}
if (! (handlerInstance instanceof URLStreamHandler)) {
throw new RuntimeException("Wrong class type, " + handlerInstance.getClass().getName());
} else {
handler = (URLStreamHandler) handlerInstance;
}
}
My override logic works as follows:
URL.setURLStreamHandlerFactory(new URLStreamHandlerFactory() {
public URLStreamHandler createURLStreamHandler(String protocol) {
URLStreamHandler urlStreamHandler = new URLStreamHandler() {
protected URLConnection openConnection(URL url) throws IOException {
return new URLConnection(url) {
public void connect() throws IOException {
Log.i(getClass().getName(), "Global URL override!!! URL load requested " + url);
}
};
}
};
return shouldHandleURL(url) ? urlStreamHandler : handler;
}
});
The override works but I cannot load the default in cases where I want normal URL connection behavior. Trying to clear my StreamHandlerFactory as follows:
URL.setURLStreamHandlerFactory(null);
Throws an error:
java.lang.Error: Factory already set
at java.net.URL.setURLStreamHandlerFactory(URL.java:112)
The only way I've been able to resolve my issue is by setting the streamHandler and StramHandler factory to null using reflection through the private fields. It's yucky but it works. This is my temporary solution (I was hoping for something less yucky):
private static class APIURLStreamHandlerFactory implements URLStreamHandlerFactory {
public URLStreamHandler createURLStreamHandler(String protocol) {
return new URLStreamHandler() {
protected URLConnection openConnection(URL url) throws IOException {
if (! shouldHandle(url)) {
Field streamHandlerMapField = getURLPrivateField("streamHandlers");
try { Map handlerMap = (Map) streamHandlerMapField.get(url); handlerMap.clear(); }
catch (IllegalAccessException e) { throw new Error("Could not access private field streamHandler",e); }
unregisterSelf();
invokeInstancePrivateMethod(url, "setupStreamHandler");
URLStreamHandler originalHandler = getPrivateUrlStreamHandler(url);
Method openConnectionMethod = getPrivateMethod(originalHandler, "openConnection", URL.class);
openConnectionMethod.setAccessible(true);
try { return (URLConnection) openConnectionMethod.invoke(originalHandler, url); }
catch (IllegalAccessException e) { throw new Error("Could not access openConnection on URL", e); }
catch (InvocationTargetException e) { throw new RuntimeException("Exception while invoking openConnection on URL", e); }
finally { registerSelf(); }
}
return new APIURLConnection(url, registeredServiceRouter);
}
};
}
private static Method getPrivateMethod(Object object, String methodName, Class... parameterTypes) {
try { return object.getClass().getDeclaredMethod(methodName, parameterTypes); }
catch (NoSuchMethodException e) { throw new Error("Could not find method " + methodName, e); }
}
private static boolean shouldHandle(URL url) {
//Logic to decide which requests to handle
}
private static URLStreamHandler getPrivateUrlStreamHandler(URL url) {
URLStreamHandler originalHandler;
try { originalHandler = (URLStreamHandler) getURLPrivateField("streamHandler").get(url); }
catch (IllegalAccessException e) { throw new Error("Could not access streamHandler field on URL",e); }
return originalHandler;
}
private static Object invokeInstancePrivateMethod(Object objectInstance, String methodName) {
try {
Method urlPrivateMethod = getURLPrivateMethod(methodName);
urlPrivateMethod.setAccessible(true);
return urlPrivateMethod.invoke(objectInstance);
}
catch (IllegalAccessException e) { throw new Error("Cannot access metehod " + methodName + " on instance type " + objectInstance.getClass().getName(), e); }
catch (InvocationTargetException e) { throw new RuntimeException("Exception while invoking method " + methodName + " on type " + objectInstance.getClass().getName(),e); }
}
private static Method getURLPrivateMethod(String methodName) {
try { return URL.class.getDeclaredMethod(methodName); }
catch (NoSuchMethodException e) { throw new Error("Method " + methodName + " not found on class URL"); }
}
#TargetApi(Build.VERSION_CODES.KITKAT)
private static void resetStreamHandlerFactory() {
try { getURLPrivateField("streamHandlerFactory").set(null, null); }
catch (IllegalAccessException e) { throw new Error("Could not access factory field on URL class: {}", e); }
}
#NonNull
private static Field getURLPrivateField(String field) {
final Field privateField;
try { privateField = URL.class.getDeclaredField(field); }
catch (NoSuchFieldException e) { throw new Error("No such field " + field + " in class URL"); }
privateField.setAccessible(true);
return privateField;
}
}
I found this in java.net.URL
else if (protocol.equals("http")) {
try {
String name = "com.android.okhttp.HttpHandler";
streamHandler = (URLStreamHandler) Class.forName(name).newInstance();
} catch (Exception e) {
throw new AssertionError(e);
}
}
It would appear com.android.okhttp.HttpHandler would be the stream handler you would want to return for default behaviour
Here are the other defaults:
if (protocol.equals("file")) {
streamHandler = new FileHandler();
} else if (protocol.equals("ftp")) {
streamHandler = new FtpHandler();
} else if (protocol.equals("http")) {
try {
String name = "com.android.okhttp.HttpHandler";
streamHandler = (URLStreamHandler) Class.forName(name).newInstance();
} catch (Exception e) {
throw new AssertionError(e);
}
} else if (protocol.equals("https")) {
try {
String name = "com.android.okhttp.HttpsHandler";
streamHandler = (URLStreamHandler) Class.forName(name).newInstance();
} catch (Exception e) {
throw new AssertionError(e);
}
} else if (protocol.equals("jar")) {
streamHandler = new JarHandler();
}
if (streamHandler != null) {
streamHandlers.put(protocol, streamHandler);
}
PS: I've been trying to solve this for the past couple hours and your post was the only one I could find wanting to do a similar thing. Hopefully this helps.
Related
I am using prosody xmpp server hosted in aws console i am trying to connect to login with my credentials but everytime i encounter the same error. I am usign smack doe this purpose.i searched through all of git and stackovrflow but couldnot find one
my mainactivity.java
private boolean register(final String paramString1,final String paramString2) {
try {
XMPP.getInstance().register(paramString1, paramString2);
return true;
} catch (XMPPException localXMPPException) {
localXMPPException.printStackTrace();
} catch (SmackException.NoResponseException e) {
e.printStackTrace();
} catch (SmackException.NotConnectedException e) {
e.printStackTrace();
}
return false;
}
private boolean login(final String user,final String pass,final String username) {
try {
XMPP.getInstance().login(user, pass, username);
sendBroadcast(new Intent("liveapp.loggedin"));
return true;
} catch (Exception e) {
e.printStackTrace();
try {
XMPP.getInstance().login(user, pass, username);
sendBroadcast(new Intent("liveapp.loggedin"));
return true;
} catch (XMPPException e1) {
e1.printStackTrace();
} catch (SmackException e1) {
e1.printStackTrace();
} catch (InterruptedException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}catch (Exception e1){
e1.printStackTrace();
}
}
return false;
}
public class UserLoginTask extends AsyncTask<Void, Void, Boolean> {
public UserLoginTask() {
}
protected Boolean doInBackground(Void... paramVarArgs) {
String mEmail = "abc";
String mUsername = "abc";
String mPassword = "welcome";
if (register(mEmail, mPassword)) {
try {
XMPP.getInstance().close();
} catch (Exception e) {
e.printStackTrace();
}
}
return login(mEmail, mPassword, mUsername);
}
protected void onCancelled() {
mAuthTask = null;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
}
protected void onPostExecute(Boolean success) {
mAuthTask = null;
try {
if (success) {
messageListener = new ChatMessageListener() {
#Override
public void processMessage(Chat chat, Message message) {
// here you will get only connected user by you
}
};
packetListener = new StanzaListener() {
#Override
public void processStanza(Stanza packet) throws SmackException.NotConnectedException, InterruptedException {
if (packet instanceof Message) {
final Message message = (Message) packet;
// here you will get all messages send by anybody
}
}
};
chatListener = new ChatManagerListener() {
#Override
public void chatCreated(Chat chatCreated, boolean local) {
}
};
try {
String opt_jidStr = "abc";
try {
opt_jid = JidCreate.bareFrom(Localpart.from(opt_jidStr), Domainpart.from(HOST));
} catch (XmppStringprepException e) {
e.printStackTrace();
}
String addr1 = XMPP.getInstance().getUserLocalPart(getApplicationContext());
String addr2 = opt_jid.toString();
if (addr1.compareTo(addr2) > 0) {
String addr3 = addr2;
addr2 = addr1;
addr1 = addr3;
}
chat = XMPP.getInstance().getThreadChat(getApplicationContext(), addr1, addr2);
if (chat == null) {
chat = XMPP.getInstance().createChat(getApplicationContext(), (EntityJid) opt_jid, addr1, addr2, messageListener);
Log.e(TAG, "chat value single chat 1 :" + chat);
} else {
chat.addMessageListener(messageListener);
Log.e(TAG, "chat value single chat 2:" + chat);
}
} catch (Exception e) {
e.printStackTrace();
}
XMPP.getInstance().addStanzaListener(getApplicationContext(), packetListener);
XMPP.getInstance().addChatListener(getApplicationContext(), chatListener);
XMPP.getInstance().getSrvDeliveryManager(getApplicationContext());
} else {
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
private void attemptLogin() {
if (mAuthTask != null) {
return;
}
boolean cancel = false;
View focusView = null;
if (cancel) {
focusView.requestFocus();
} else {
try {
mAuthTask = new UserLoginTask();
mAuthTask.execute((Void) null);
} catch (Exception e) {
}
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash_screen);
databaseReference = FirebaseDatabase.getInstance().getReference().child("UserInfo");
attemptLogin();
}
}
XMPP.java file
private XMPPTCPConnectionConfiguration buildConfiguration() throws XmppStringprepException {
XMPPTCPConnectionConfiguration.Builder builder =
XMPPTCPConnectionConfiguration.builder();
builder.setHost(HOST);
builder.setPort(PORT);
builder.setCompressionEnabled(false);
builder.setSecurityMode(ConnectionConfiguration.SecurityMode.disabled);
builder.setSendPresence(true);
DomainBareJid serviceName = JidCreate.domainBareFrom(HOST);
builder.setServiceName(serviceName);
return builder.build();
}
private XMPPTCPConnection getConnection() throws XMPPException, SmackException, IOException, InterruptedException {
Log.e(TAG, "Getting XMPP Connect");
if (isConnected()) {
Log.e(TAG, "Returning already existing connection");
return this.connection;
}
long l = System.currentTimeMillis();
try {
if(this.connection != null){
Log.e(TAG, "Connection found, trying to connect");
this.connection.connect();
}else{
Log.e(TAG, "No Connection found, trying to create a new connection");
XMPPTCPConnectionConfiguration config = buildConfiguration();
SmackConfiguration.DEBUG = true;
this.connection = new XMPPTCPConnection(config);
this.connection.connect();
}
} catch (Exception e) {
Log.e(TAG,"some issue with getting connection :" + e.getMessage());
}
Log.e(TAG, "Connection Properties: " + connection.getHost());
Log.e(TAG, "Time taken in first time connect: " + (System.currentTimeMillis() - l));
return this.connection;
}
public static XMPP getInstance() {
if (instance == null) {
synchronized (XMPP.class) {
if (instance == null) {
instance = new XMPP();
}
}
}
return instance;
}
public void close() {
Log.e(TAG, "Inside XMPP close method");
if (this.connection != null) {
this.connection.disconnect();
}
}
private XMPPTCPConnection connectAndLogin(Context context) {
Log.e(TAG, "Inside connect and Login");
if (!isConnected()) {
Log.e(TAG, "Connection not connected, trying to login and connect");
try {
String username = "user1";
String password = "qwerty123";
this.connection = getConnection();
Log.e(TAG, "XMPP username :" + username);
Log.e(TAG, "XMPP password :" + password);
this.connection.login(username, password);
Log.e(TAG, "Connect and Login method, Login successful");
context.sendBroadcast(new Intent(ACTION_LOGGED_IN));
} catch (XMPPException localXMPPException) {
Log.e(TAG, "Error in Connect and Login Method1");
localXMPPException.printStackTrace();
} catch (SmackException e) {
Log.e(TAG, "Error in Connect and Login Method2");
Log.e(TAG, e.getMessage());
e.printStackTrace();
} catch (IOException e) {
Log.e(TAG, "Error in Connect and Login Method3");
e.printStackTrace();
} catch (InterruptedException e) {
Log.e(TAG, "Error in Connect and Login Method4");
e.printStackTrace();
} catch (IllegalArgumentException e) {
Log.e(TAG, "Error in Connect and Login Method5");
e.printStackTrace();
} catch (Exception e) {
Log.e(TAG, "Error in Connect and Login Method6");
e.printStackTrace();
}
}
Log.e(TAG, "Inside getConnection - Returning connection");
return this.connection;
}
public boolean isConnected() {
return (this.connection != null) && (this.connection.isConnected());
}
public EntityFullJid getUser() {
if (isConnected()) {
return connection.getUser();
} else {
return null;
}
}
public void login(String user, String pass, String username)
throws XMPPException, SmackException, IOException, InterruptedException, XMPPException {
Log.e(TAG, "inside XMPP getlogin Method");
long l = System.currentTimeMillis();
XMPPTCPConnection connect = getConnection();
if (connect.isAuthenticated()) {
Log.e(TAG, "User already logged in");
return;
}
Log.e(TAG, "Time taken to connect: " + (System.currentTimeMillis() - l));
l = System.currentTimeMillis();
try{
connect.login(user, pass);
}catch (Exception e){
Log.e(TAG, "Issue in login, check the stacktrace");
Log.e(TAG, e.getMessage());
e.printStackTrace();
}
Log.e(TAG, "Time taken to login: " + (System.currentTimeMillis() - l));
Log.e(TAG, "login step passed");
PingManager pingManager = PingManager.getInstanceFor(connect);
pingManager.setPingInterval(10000);
}
public void register(String user, String pass) throws XMPPException, SmackException.NoResponseException, SmackException.NotConnectedException {
Log.e(TAG, "inside XMPP register method, " + user + " : " + pass);
long l = System.currentTimeMillis();
try {
AccountManager accountManager = AccountManager.getInstance(getConnection());
accountManager.sensitiveOperationOverInsecureConnection(true);
accountManager.createAccount(Localpart.from(user), pass);
} catch (SmackException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (XMPPException e) {
e.printStackTrace();
}
Log.e(TAG, "Time taken to register: " + (System.currentTimeMillis() - l));
}
public String getUserLocalPart(Context context){
return connectAndLogin(context).getUser().getLocalpart().toString();
}
public EntityFullJid getUser(Context context){
return connectAndLogin(context).getUser();
}
}
error i am getting
E/XMPP-EXAMPLE: Client is not, or no longer, connected. Did you call connect() before login()?
org.jivesoftware.smack.SmackException$NotConnectedException: Client is not, or no longer, connected. Did you call connect() before login()?
at org.jivesoftware.smack.AbstractXMPPConnection.throwNotConnectedExceptionIfAppropriate(AbstractXMPPConnection.java:667) at org.jivesoftware.smack.AbstractXMPPConnection.login(AbstractXMPPConnection.java:512)
at org.jivesoftware.smack.AbstractXMPPConnection.login(AbstractXMPPConnection.java:491)
at xmpp.XMPP.connectAndLogin(XMPP.java:120)
at xmpp.XMPP.removeChatListener(XMPP.java:226)
at SplashScreenActivity.onDestroy(SplashScreenActivity.java:255)
at android.app.Activity.performDestroy(Activity.java:7068)
at android.app.Instrumentation.callActivityOnDestroy(Instrumentation.java:1154)
at android.app.ActivityThread.performDestroyActivity(ActivityThread.java:4280)
at android.app.ActivityThread.handleDestroyActivity(ActivityThread.java:4311)
at android.app.ActivityThread.-wrap6(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1586)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:163)
at android.app.ActivityThread.main(ActivityThread.java:6238)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:933)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:823)
The message is clear, you are calling connection's login(...) before you establish actual connection. It might be caused by loss of connection immediately at connection before calling login. Since you just threw your code at us instead of making a minimal example, I could not follow. Also I have stopped used async task long ago, making it even harder to follow. Here is an example made with MVVM and Coroutine
class ChatsViewModel(val app: Application) : AndroidViewModel(app) {
private val chatApp: App = app as App
fun getConnection(): XMPPTCPConnection? {
return chatApp.xmppConnection
}
fun login(username: String, password: String) = viewModelScope.launch(Dispatchers.IO) {
if(chatApp.xmppConnection !=null && chatApp.xmppConnection!!.isAuthenticated) return#launch
val config = XMPPTCPConnectionConfiguration.builder()
.setUsernameAndPassword(username, password)
.setHostAddress(InetAddress.getByName("192.168.1.102"))
.setXmppDomain(JidCreate.domainBareFrom(Constants.JABBER_DOMAIN))
.setSecurityMode(ConnectionConfiguration.SecurityMode.disabled)
.setPort(5222)
.enableDefaultDebugger()
.build()
val conn = XMPPTCPConnection(config)
try {
conn.connect()
} catch (e: Exception) {
//conn failed
}
if (!conn.isConnected) {
//alert use is not connected
}else{
try {
conn.login()
} catch (e: Exception) {
//failed to login
}
if (!conn.isAuthenticated) {
//alert user he is not logged in
}
else {
chatApp.xmppConnection = conn
//do your thing here. As example we are
//going to send presence stanza
val presence = Presence(Presence.Type.available)
presence.status = "Gone fishing"
try {
getConnection()?.sendStanza(presence)
} catch (e: Exception) {
//sending failed
}
and here is how you will use that view model in a fragment (or Activity)
class ChatsFragment : Fragment() {
private lateinit var chatsViewModel: ChatsViewModel
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
chatsViewModel = ViewModelProvider(requireActivity()).get(ChatsViewModel::class.java)
val root = inflater.inflate(R.layout.fragment_chats, container, false)
return root
}
override fun onResume() {
super.onResume()
chatsViewModel.login("xmpp_id_local_part", "123456")
}
override fun onStop() {
super.onStop()
chatsViewModel.logout()
}
}
}
}
}
}
I have the following code to connect to a Bluetooth device:
class BiSymConnectThread extends Thread {
BluetoothDevice mDevice;
public BiSymConnectThread(BluetoothDevice device) throws SecurityException, NoSuchMethodException {
mDevice = device;
UUID uuid = mDevice.getUuids()[0].getUuid();
try {
biSymSocket = mDevice.createInsecureRfcommSocketToServiceRecord(uuid);
} catch (IOException e) {
Log.e("Error", "Could not connect!");
}
}
public void cancel() {
interrupt();
try {
Log.i("Treadmill", "in connect thread cancellation");
if (biSymSocket != null) {
biSymSocket.close();
}
} catch (IOException localIOException) {
Log.e("Treadmill", "exception + " + localIOException.getMessage());
}
}
public void run() {
try {
if (biSymSocket.isConnected()) {
biSymSocket.close();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new IOException();
}
}
biSymSocket.connect();
eventHandler.obtainMessage(MESSAGE_CONNECT_BISYM, 0, 0, "").sendToTarget();
BluetoothConnectionService.setSocket(biSymSocket);
BluetoothConnectionService.sendMessage(biSymSocket, "S");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Log.e("Error", "InterruptedException: " + e.getMessage(), e);
throw new IOException();
}
} catch (IOException e) {
Log.e("Error", "IOException: " + e.getMessage(), e);
eventHandler.obtainMessage(MESSAGE_ERRORCONNECT_BISYM, 0, 0, "").sendToTarget();
if (biSymSocket != null) {
try {
biSymSocket.close();
} catch (IOException e1) {
Log.e("Error", "Can't close socket!");
}
}
}
synchronized (this) {
biSymConnectThread = null;
}
}
}
If I attempt to reconnect to the device, I get the following error:
RFCOMM_CreateConnection - already opened state:2, RFC state:4, MCB state:5
In the other question asking about this error, someone mentions the isConnected() method. However, in my case, isConnected() returns false and the connection still fails.
Does anyone know what is the problem here? It appears this is some obscure error, since there doesn't seem to be anything on the web about this.
I have the following code, and all works fine when I can connect to the server:
public void getXMLData()
{
if (skipUpdate)
{
skipUpdate=false;
return;
}
skipUpdate=true;
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
int SERVERPORT=0;
try {
SERVERPORT = Integer.parseInt(prefs.getString("pref_key_port_1","Port"));
} catch (NumberFormatException e) {
txtStatus.setText("Invalid Port Number");
return;
}
String SERVERHOST = prefs.getString("pref_key_host_1","127.0.0.1");
String PASSWORD = prefs.getString("pref_key_pass_1", "password");
try {
XMLFetcherTask myXMLFetcherTask = new XMLFetcherTask(SERVERHOST,SERVERPORT,PASSWORD);
myXMLFetcherTask.execute();
} catch (Exception e) {
txtStatus.setText("Error "+e.getMessage());
return;
}
skipUpdate=false;
}
public class XMLFetcherTask extends AsyncTask<Void, Void, Void> {
String dstAddress;
int dstPort;
String response = "";
String password="";
XMLFetcherTask(String addr, int port, String pass){
dstAddress = addr;
dstPort = port;
password=pass;
}
#Override
protected Void doInBackground(Void... arg0) {
Socket socket = null;
try {
socket = new Socket(dstAddress, dstPort);
PrintWriter out = new PrintWriter(new BufferedWriter(
new OutputStreamWriter(socket.getOutputStream())),
true);
out.println(password);
response="";
BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
while (response.toLowerCase().indexOf("</response>")<0)
{
response+=input.readLine();
}
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
txtStatus.setText("UnknownHostException: " + e.getMessage());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
txtStatus.setText("IOException: " + e.getMessage());
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
txtStatus.setText("Exception: " + e.getMessage());
} finally{
try {
socket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
//txtStatus.setText("Exception Finally: " + e.getMessage());
}
}
return null;
}
#Override
protected void onPostExecute(Void result) {
if( !(response.substring(0,5).equalsIgnoreCase("<resp") || response.substring(0,5).equalsIgnoreCase("<?xml")) ) //!response.substring(0,5).equalsIgnoreCase("<?xml") ||
{
txtStatus.setText("Server response doesn't look XML, please check password: '"+response.substring(0,5)+"'");
} else {
lastXMLData=response;
txtStatus.setText("Resp Len: " + response.length());
skipUpdate=false;
updateFragmentListeners();
}
super.onPostExecute(result);
}
}
Now, when I get UnknownHostException, the app force close with following stack trace:
07-29 15:52:08.754 1525-1538/android.process.acore V/BackupServiceBinder﹕ doBackup() invoked
07-29 15:52:08.766 1525-1538/android.process.acore E/DictionaryBackupAgent﹕ Couldn't read from the cursor
07-29 16:29:55.178 1525-1534/android.process.acore E/StrictMode﹕ A resource was acquired at attached stack trace but never released. See java.io.Closeable for information on avoiding resource leaks.
java.lang.Throwable: Explicit termination method 'close' not called
at dalvik.system.CloseGuard.open(CloseGuard.java:184)
at android.os.ParcelFileDescriptor.<init>(ParcelFileDescriptor.java:180)
at android.os.ParcelFileDescriptor$1.createFromParcel(ParcelFileDescriptor.java:916)
at android.os.ParcelFileDescriptor$1.createFromParcel(ParcelFileDescriptor.java:906)
at android.app.IBackupAgent$Stub.onTransact(IBackupAgent.java:71)
at android.os.Binder.execTransact(Binder.java:446)
07-29 16:29:55.178 1525-1534/android.process.acore E/StrictMode﹕ A resource was acquired at attached stack trace but never released. See java.io.Closeable for information on avoiding resource leaks.
java.lang.Throwable: Explicit termination method 'close' not called
at dalvik.system.CloseGuard.open(CloseGuard.java:184)
at android.os.ParcelFileDescriptor.<init>(ParcelFileDescriptor.java:180)
at android.os.ParcelFileDescriptor$1.createFromParcel(ParcelFileDescriptor.java:916)
at android.os.ParcelFileDescriptor$1.createFromParcel(ParcelFileDescriptor.java:906)
at android.app.IBackupAgent$Stub.onTransact(IBackupAgent.java:64)
at android.os.Binder.execTransact(Binder.java:446)
07-29 16:29:55.178 1525-1534/android.process.acore E/StrictMode﹕ A resource was acquired at attached stack trace but never released. See java.io.Closeable for information on avoiding resource leaks.
java.lang.Throwable: Explicit termination method 'close' not called
at dalvik.system.CloseGuard.open(CloseGuard.java:184)
at android.os.ParcelFileDescriptor.<init>(ParcelFileDescriptor.java:180)
at android.os.ParcelFileDescriptor$1.createFromParcel(ParcelFileDescriptor.java:916)
at android.os.ParcelFileDescriptor$1.createFromParcel(ParcelFileDescriptor.java:906)
at android.app.IBackupAgent$Stub.onTransact(IBackupAgent.java:57)
at android.os.Binder.execTransact(Binder.java:446)
I have no idea why this happen...
I tried to comment hte txtStatus.setText as normally it's not supposed to work from another thread, but no change.
Tested on android emulator with framework 22 and on my phone with framework 21.
Any idea would be welcome
Ok I manage to make it work using threads instead, here's final code:
public void getXMLData()
{
if (skipUpdate)
{
skipUpdate=false;
return;
}
skipUpdate=true;
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
int SERVERPORT=0;
try {
SERVERPORT = Integer.parseInt(prefs.getString("pref_key_port_1","Port"));
} catch (NumberFormatException e) {
txtStatus.setText("Invalid Port Number");
return;
}
String SERVERHOST = prefs.getString("pref_key_host_1","127.0.0.1");
String PASSWORD = prefs.getString("pref_key_pass_1", "password");
try {
// XMLFetcherTask myXMLFetcherTask = new XMLFetcherTask(SERVERHOST,SERVERPORT,PASSWORD);
// myXMLFetcherTask.execute();
XMLFetcherTask XMLFetcherTaskThread = new XMLFetcherTask();
XMLFetcherTaskThread.dstAddress=SERVERHOST;
XMLFetcherTaskThread.dstPort=SERVERPORT;
XMLFetcherTaskThread.password=PASSWORD;
Thread cThread = new Thread(XMLFetcherTaskThread);
cThread.start();
} catch (Exception e) {
txtStatus.setText("Error "+e.getMessage());
return;
}
skipUpdate=false;
}
public class XMLFetcherTask implements Runnable {
String dstAddress;
int dstPort;
String response = "";
String password="";
private void setStatusFromThread(final String status)
{
runOnUiThread(new Runnable() {
#Override
public void run() {
setStatus(status);
}
});
}
private void updateListenersThread()
{
runOnUiThread(new Runnable() {
#Override
public void run() {
updateFragmentListeners();
}
});
}
public void run() {
Socket socket = null;
//BufferedReader input = null;
//PrintWriter out = null;
try {
socket = new Socket(dstAddress, dstPort);
PrintWriter out = new PrintWriter(new BufferedWriter(
new OutputStreamWriter(socket.getOutputStream())),
true);
out.println(password);
response="";
BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
while (response.toLowerCase().indexOf("</response>") < 0) {
response+=input.readLine();
}
if( !(response.substring(0,5).equalsIgnoreCase("<resp") || response.substring(0,5).equalsIgnoreCase("<?xml")) ) //!response.substring(0,5).equalsIgnoreCase("<?xml") ||
{
setStatusFromThread("Server response doesn't look XML, please check password: '" + response.substring(0, 5) + "'");
} else {
lastXMLData=response;
Date dNow = new Date( );
SimpleDateFormat ft = new SimpleDateFormat ("hh:mm:ss");
setStatusFromThread("Last update: " + ft.format(dNow));
skipUpdate=false;
updateListenersThread();
}
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
setStatusFromThread("UnknownHostException: " + e.getMessage());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
setStatusFromThread("IOException: " + e.getMessage());
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
setStatusFromThread("Exception: " + e.getMessage());
} finally{
try {
socket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
//txtStatus.setText("Exception Finally: " + e.getMessage());
} catch (Exception e) {
// TODO Auto-generated catch block
}
}
}
}
I want to list all the files that my google accouunts have with my app, i tried the follow piece of code which is actually from the website, but , there's error in the line " FileList fileList = request.execute(); ", it says the method execute() is undefined for the type Drive.Files.List ,i don't know how to fix it.
private void getDriveContents()
{
Thread t = new Thread(new Runnable()
{
#Override
public void run()
{
com.google.api.services.drive.Drive.Files f1 = mService.files();
Files.List request = null;
do
{
try
{
request = service.files().list().setQ("trashed=false");
FileList fileList = request.execute();
mResultList.addAll(fileList.getItems());
request.setPageToken(fileList.getNextPageToken());
} catch (UserRecoverableAuthIOException e) {
startActivityForResult(e.getIntent(), REQUEST_AUTHORIZATION);
} catch (IOException e) {
e.printStackTrace();
if (request != null)
{
request.setPageToken(null);
}
}
} while (request.getPageToken() !=null && request.getPageToken().length() > 0);
populateListView();
}
});
t.start();
}
I believe your 'request' is of incorrect type. it is supposed to be FileList, not File.List
I wasn't arguing about what you've seen. I was only trying to help since I have similar code running and tested. Here's a snippet from my "class ListDownFromGOODrive extends AsyncTask..."
import com.google.api.services.drive.model.FileList;
...
.... a lot of code here
...
GoogleAccountCredential _crd;
Drive _svc;
FileList _gooLst;
Intent _it;
String _rqst;
...
... a lot of code here
...
#Override protected Integer doInBackground(Void... nothing) {
try {
if (_crd == null)
_crd = GoogleAccountCredential.usingOAuth2(_ctx,Arrays.asList(DriveScopes.DRIVE_FILE));
if (_svc == null)
_svc = new Drive.Builder
(AndroidHttp.newCompatibleTransport(), new GsonFactory(), _crd).build();
if (_crd.getSelectedAccountName() == null) {
_it = _crd.newChooseAccountIntent();
return REQ_EMAIL;
}
_gooLst = _svc.files().list().setMaxResults(MAX_DOWN).setQ(_rqst)
.setFields("items(id,title,description,downloadUrl,thumbnailLink)").execute();
}
catch (UserRecoverableAuthIOException e){ //Log.d("atn", "LD URAIO Except->REQ_AUTH");
try { _it = e.getIntent(); } catch (Exception e1) {return ERROR;}
return REQ_AUTH;
}
catch (IOException e) { return ERROR; }
catch (Exception e) { return ERROR; }
return GOOD;
}
it returns GOOD, ERROR, REQ_AUTH(orization), or REQ_EMAIL(account)
my HttpGet request is calling my indexAction, instead of getAction. What's going on?
Here are my codes:
public function getAction() {
$id = $this->_getParam('id');
if(!$id)
{
$this->getResponse()
->setHttpResponseCode(400)
->setBody("no id");
return;
}
try
{
$q = Doctrine_Query::create()
->from('Milotin_Model_Locations l')
->where ('l.id=?', $id);
$result = $q->fetchArray();
if(count($result) == 1)
{
$this->getResponse()
->setHttpResponseCode(200)
->setBody(json_encode($result));
}
}
catch(Exception $e)
{
$this->getResponse()
->setHttpResponseCode(500)
->setBody($e->getMessage());
}
}
public function indexAction() {
}
And here is my code in Android:
private static void getLoc()
{
final HttpResponse response;
final HttpGet getRequest = new HttpGet(LOCATION_URI + "?geolat=" + geoLat + "&geolong=" + geoLong);
try {
response = mHttpClient.execute(getRequest);
if(response.getStatusLine().getStatusCode() == 200)
{
//do something
}
} catch (ClientProtocolException e) {
Log.e(TAG, e.getMessage());
e.printStackTrace();
} catch (IOException e) {
Log.e(TAG, e.getMessage());
e.printStackTrace();
} catch (JSONException e) {
Log.e(TAG, e.getMessage());
e.printStackTrace();
}
}
My HttpPost is working correctly (it calls postAction), Any explanation?
Thanks.
I found the answer. It's actually the behavior of Zend Framework. If the 'id' element is not found in the GET request, it will redirect to indexAction, instead of getAction.
Example:
'GET localhost/student' will redirected to indexAction, while
'GET localhost/student/23' will redirected to getAction. (23 is the id)
Found it in Zend Framework: A beginner's guide, by Vikram Vaswani.