/*
* Copyright 2014 Bevbot LLC <info@bevbot.com>
*
* This file is part of the Kegtab package from the Kegbot project. For
* more information on Kegtab or Kegbot, see <http://kegbot.org/>.
*
* Kegtab 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, version 2.
*
* Kegtab 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 Kegtab. If not, see <http://www.gnu.org/licenses/>.
*/
package org.kegbot.app.setup;
import android.app.Fragment;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.SystemClock;
import android.text.util.Linkify;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import org.kegbot.api.KegbotApiException;
import org.kegbot.api.KegbotApiImpl;
import org.kegbot.app.KegbotApplication;
import org.kegbot.app.R;
import org.kegbot.app.config.AppConfiguration;
import java.util.concurrent.atomic.AtomicBoolean;
import butterknife.ButterKnife;
public class SetupPairStep extends SetupStep {
private final String TAG = SetupPairStep.class.getSimpleName();
private final Fragment mContentFragment = new Fragment() {
private final AtomicBoolean mQuit = new AtomicBoolean();
private TextView mPairingPrompt;
private TextView mPairingUrl;
private TextView mPairingPromptContinued;
private TextView mPairingCodeText;
private TextView mPairingCompleteText;
private AsyncTask<Void, Void, String> mPollTask;
private String mPairingCode;
private final Handler mHandler = new Handler(Looper.getMainLooper());
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.setup_pair_fragment, null);
return view;
}
@Override
public void onStart() {
super.onStart();
final View view = getView();
mPairingPrompt = ButterKnife.findById(view, R.id.pairingPleaseVisit);
mPairingUrl = ButterKnife.findById(view, R.id.pairingUrl);
mPairingPromptContinued = ButterKnife.findById(view, R.id.pairingAndEnter);
mPairingCodeText = ButterKnife.findById(view, R.id.pairingCode);
mPairingCompleteText = ButterKnife.findById(view, R.id.pairingComplete);
onPairingStarted();
startPolling();
final AppConfiguration config = KegbotApplication.get(getActivity()).getConfig();
final String baseUrl = KegbotApplication.get(getActivity()).getConfig().getKegbotUrl();
final String addUrl = baseUrl + "/link";
mPairingUrl.setText(addUrl);
Linkify.addLinks(mPairingUrl, Linkify.ALL);
}
@Override
public void onStop() {
super.onStop();
stopPolling();
}
private void startPolling() {
Preconditions.checkState(mPollTask == null, "Already running");
final AppConfiguration config = KegbotApplication.get(getActivity()).getConfig();
final KegbotApiImpl api = KegbotApiImpl.fromContext(getActivity());
mQuit.set(false);
mPollTask = new AsyncTask<Void, Void, String>() {
private Exception mError;
@Override
protected String doInBackground(Void... voids) {
while (!mQuit.get()) {
if (Strings.isNullOrEmpty(mPairingCode)) {
try {
mPairingCode = api.startDeviceLink(Build.MODEL);
mHandler.post(new Runnable() {
@Override
public void run() {
mPairingCodeText.setText(mPairingCode);
}
});
} catch (KegbotApiException e) {
mError = e;
return "";
}
}
while (!mQuit.get()) {
try {
Log.d(TAG, "Checking pairing status ...");
final String apiKey = api.pollDeviceLink(mPairingCode);
if (!Strings.isNullOrEmpty(apiKey)) {
return apiKey;
}
} catch (KegbotApiException e) {
Log.w(TAG, "Error checking pairing code: " + e, e);
mError = e;
mPairingCode = ""; // fetch a new code next time
break;
}
SystemClock.sleep(1000);
}
Log.w(TAG, "Pairing aborted unexpectedly, retrying in 1s.");
SystemClock.sleep(1000);
}
return null;
}
@Override
protected void onPostExecute(String s) {
if (mError != null) {
onPairingFailed(mError);
return;
}
if (Strings.isNullOrEmpty(s)) {
// We quit.
return;
}
config.setApiKey(s);
onPairingComplete();
}
};
mPollTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
private void stopPolling() {
Preconditions.checkState(mPollTask != null, "Not running.");
mQuit.set(true);
mPollTask = null;
}
private void onPairingStarted() {
mState.setNextButtonEnabled(false);
mPairingPrompt.setVisibility(View.VISIBLE);
mPairingUrl.setVisibility(View.VISIBLE);
mPairingPromptContinued.setVisibility(View.VISIBLE);
mPairingCodeText.setVisibility(View.VISIBLE);
mPairingCompleteText.setVisibility(View.GONE);
}
private void onPairingComplete() {
mState.setNextButtonEnabled(true);
mPairingPrompt.setVisibility(View.GONE);
mPairingUrl.setVisibility(View.GONE);
mPairingPromptContinued.setVisibility(View.GONE);
mPairingCodeText.setVisibility(View.GONE);
mPairingCompleteText.setVisibility(View.VISIBLE);
}
private void onPairingFailed(Exception error) {
if (error != null) {
Log.e(TAG, "Failed to pair: " + error, error);
} else {
Log.e(TAG, "Pairing failed, error unknown");
}
}
};
public SetupPairStep(SetupActivity.SetupState state) {
super(state);
}
@Override
public Fragment getContentFragment() {
return mContentFragment;
}
@Override
public Fragment getControlsFragment() {
return null;
}
@Override
public SetupStep advance() throws SetupValidationException {
final AppConfiguration config = KegbotApplication.get(mContentFragment.getActivity()).getConfig();
return new SetupManagerPinStep(mState);
}
}