/* * Copyright (c) 2011, 2012 Roberto Tyley * * This file is part of 'Agit' - an Android Git client. * * Agit is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Agit is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see http://www.gnu.org/licenses/ . */ package com.madgag.agit.ssh; import static android.content.Context.BIND_AUTO_CREATE; import static java.util.concurrent.TimeUnit.SECONDS; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.os.IBinder; import android.os.RemoteException; import android.util.Log; import com.google.inject.Inject; import com.google.inject.Provider; import com.google.inject.name.Named; import com.madgag.ssh.android.authagent.AndroidAuthAgent; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class AndroidAuthAgentProvider implements Provider<AndroidAuthAgent> { protected static final String TAG = "AAAP"; private final Lock lock = new ReentrantLock(); private final Condition authAgentBound = lock.newCondition(); // TODO CountDownLatch or // AbstractQueuedSynchronizer varient? private AndroidAuthAgent authAgent; private final Provider<ComponentName> preferredAuthAgentComponentNameProvider; @Inject public AndroidAuthAgentProvider( Context context, @Named("authAgent") Provider<ComponentName> preferredAuthAgentComponentNameProvider) { this.preferredAuthAgentComponentNameProvider = preferredAuthAgentComponentNameProvider; bindSshAgentTo(context); } public AndroidAuthAgent get() { waitForAuthAgentBind(); return authAgent; } private void bindSshAgentTo(Context context) { Intent intent = new Intent("org.openintents.ssh.BIND_SSH_AGENT_SERVICE"); intent.setComponent(preferredAuthAgentComponentNameProvider.get()); context.bindService(intent, new ServiceConnection() { public void onServiceDisconnected(ComponentName name) { Log.i(TAG, "onServiceDisconnected() : Lost " + authAgent); authAgent = null; } public void onServiceConnected(ComponentName name, IBinder binder) { Log.i(TAG, "onServiceConnected() : componentName=" + name + " binder=" + binder); authAgent = AndroidAuthAgent.Stub.asInterface(binder); // showDebugInfoForAuthAgent(); Showing this info is actually a bit confusing signalAuthAgentBound(); } }, BIND_AUTO_CREATE); Log.i(TAG, "made request using context " + context + " to bind to the SSH_AGENT_SERVICE"); } private void waitForAuthAgentBind() { lock.lock(); Log.d(TAG, "waitForAuthAgentBind() entered: agent=" + authAgent); try { if (authAgent != null) { Log.d(TAG, "Already got non-null agent=" + authAgent + " -no need to wait."); return; } boolean gotAgentBeforeTimeOut = authAgentBound.await(5, SECONDS); Log.d(TAG, "gotAgentBeforeTimeOut=" + gotAgentBeforeTimeOut + " agent=" + authAgent); } catch (InterruptedException e) { Log.e(TAG, "Interrupted waiting for AndroidAuthAgent", e); } finally { lock.unlock(); } } private void signalAuthAgentBound() { lock.lock(); try { authAgentBound.signal(); } finally { lock.unlock(); } } private void showDebugInfoForAuthAgent() { Log.d(TAG, "authAgent=" + authAgent); try { Log.d(TAG, "authAgent.getIdentities()=" + authAgent.getIdentities()); } catch (RemoteException e) { e.printStackTrace(); } } }