package de.danoeh.antennapod.activity.gpoddernet; import android.content.Context; import android.content.Intent; import android.content.res.Configuration; import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; import android.support.v7.app.ActionBarActivity; import android.util.Log; import android.view.LayoutInflater; import android.view.MenuItem; import android.view.View; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.EditText; import android.widget.ProgressBar; import android.widget.Spinner; import android.widget.TextView; import android.widget.ViewFlipper; import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicReference; import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.R; import de.danoeh.antennapod.activity.MainActivity; import de.danoeh.antennapod.core.gpoddernet.GpodnetService; import de.danoeh.antennapod.core.gpoddernet.GpodnetServiceException; import de.danoeh.antennapod.core.gpoddernet.model.GpodnetDevice; import de.danoeh.antennapod.core.preferences.GpodnetPreferences; import de.danoeh.antennapod.core.preferences.UserPreferences; import de.danoeh.antennapod.core.service.GpodnetSyncService; /** * Guides the user through the authentication process * Step 1: Request username and password from user * Step 2: Choose device from a list of available devices or create a new one * Step 3: Choose from a list of actions */ public class GpodnetAuthenticationActivity extends ActionBarActivity { private static final String TAG = "GpodnetAuthActivity"; private static final String CURRENT_STEP = "current_step"; private ViewFlipper viewFlipper; private static final int STEP_DEFAULT = -1; private static final int STEP_LOGIN = 0; private static final int STEP_DEVICE = 1; private static final int STEP_FINISH = 2; private int currentStep = -1; private GpodnetService service; private volatile String username; private volatile String password; private volatile GpodnetDevice selectedDevice; View[] views; @Override protected void onCreate(Bundle savedInstanceState) { setTheme(UserPreferences.getTheme()); super.onCreate(savedInstanceState); getSupportActionBar().setDisplayHomeAsUpEnabled(true); setContentView(R.layout.gpodnetauth_activity); service = new GpodnetService(); viewFlipper = (ViewFlipper) findViewById(R.id.viewflipper); LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); views = new View[]{ inflater.inflate(R.layout.gpodnetauth_credentials, viewFlipper, false), inflater.inflate(R.layout.gpodnetauth_device, viewFlipper, false), inflater.inflate(R.layout.gpodnetauth_finish, viewFlipper, false) }; for (View view : views) { viewFlipper.addView(view); } advance(); } @Override protected void onDestroy() { super.onDestroy(); if (service != null) { service.shutdown(); } } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case android.R.id.home: finish(); return true; } return super.onOptionsItemSelected(item); } @Override public void onConfigurationChanged(Configuration newConfig) { } private void setupLoginView(View view) { final EditText username = (EditText) view.findViewById(R.id.etxtUsername); final EditText password = (EditText) view.findViewById(R.id.etxtPassword); final Button login = (Button) view.findViewById(R.id.butLogin); final TextView txtvError = (TextView) view.findViewById(R.id.txtvError); final ProgressBar progressBar = (ProgressBar) view.findViewById(R.id.progBarLogin); login.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { final String usernameStr = username.getText().toString(); final String passwordStr = password.getText().toString(); if (BuildConfig.DEBUG) Log.d(TAG, "Checking login credentials"); AsyncTask<GpodnetService, Void, Void> authTask = new AsyncTask<GpodnetService, Void, Void>() { volatile Exception exception; @Override protected void onPreExecute() { super.onPreExecute(); login.setEnabled(false); progressBar.setVisibility(View.VISIBLE); txtvError.setVisibility(View.GONE); } @Override protected void onPostExecute(Void aVoid) { super.onPostExecute(aVoid); login.setEnabled(true); progressBar.setVisibility(View.GONE); if (exception == null) { advance(); } else { txtvError.setText(exception.getCause().getMessage()); txtvError.setVisibility(View.VISIBLE); } } @Override protected Void doInBackground(GpodnetService... params) { try { params[0].authenticate(usernameStr, passwordStr); GpodnetAuthenticationActivity.this.username = usernameStr; GpodnetAuthenticationActivity.this.password = passwordStr; } catch (GpodnetServiceException e) { e.printStackTrace(); exception = e; } return null; } }; if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.GINGERBREAD_MR1) { authTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, service); } else { authTask.execute(); } } }); } private void setupDeviceView(View view) { final EditText deviceID = (EditText) view.findViewById(R.id.etxtDeviceID); final EditText caption = (EditText) view.findViewById(R.id.etxtCaption); final Button createNewDevice = (Button) view.findViewById(R.id.butCreateNewDevice); final Button chooseDevice = (Button) view.findViewById(R.id.butChooseExistingDevice); final TextView txtvError = (TextView) view.findViewById(R.id.txtvError); final ProgressBar progBarCreateDevice = (ProgressBar) view.findViewById(R.id.progbarCreateDevice); final Spinner spinnerDevices = (Spinner) view.findViewById(R.id.spinnerChooseDevice); // load device list final AtomicReference<List<GpodnetDevice>> devices = new AtomicReference<>(); new AsyncTask<GpodnetService, Void, List<GpodnetDevice>>() { private volatile Exception exception; @Override protected void onPreExecute() { super.onPreExecute(); chooseDevice.setEnabled(false); spinnerDevices.setEnabled(false); createNewDevice.setEnabled(false); } @Override protected void onPostExecute(List<GpodnetDevice> gpodnetDevices) { super.onPostExecute(gpodnetDevices); if (gpodnetDevices != null) { List<String> deviceNames = new ArrayList<>(); for (GpodnetDevice device : gpodnetDevices) { deviceNames.add(device.getCaption()); } spinnerDevices.setAdapter(new ArrayAdapter<>(GpodnetAuthenticationActivity.this, android.R.layout.simple_spinner_dropdown_item, deviceNames)); spinnerDevices.setEnabled(true); if (!deviceNames.isEmpty()) { chooseDevice.setEnabled(true); } devices.set(gpodnetDevices); deviceID.setText(generateDeviceID(gpodnetDevices)); createNewDevice.setEnabled(true); } } @Override protected List<GpodnetDevice> doInBackground(GpodnetService... params) { try { return params[0].getDevices(username); } catch (GpodnetServiceException e) { e.printStackTrace(); exception = e; return null; } } }.execute(service); createNewDevice.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (checkDeviceIDText(deviceID, caption, txtvError, devices.get())) { final String deviceStr = deviceID.getText().toString(); final String captionStr = caption.getText().toString(); new AsyncTask<GpodnetService, Void, GpodnetDevice>() { private volatile Exception exception; @Override protected void onPreExecute() { super.onPreExecute(); createNewDevice.setEnabled(false); chooseDevice.setEnabled(false); progBarCreateDevice.setVisibility(View.VISIBLE); txtvError.setVisibility(View.GONE); } @Override protected void onPostExecute(GpodnetDevice result) { super.onPostExecute(result); createNewDevice.setEnabled(true); chooseDevice.setEnabled(true); progBarCreateDevice.setVisibility(View.GONE); if (exception == null) { selectedDevice = result; advance(); } else { txtvError.setText(exception.getMessage()); txtvError.setVisibility(View.VISIBLE); } } @Override protected GpodnetDevice doInBackground(GpodnetService... params) { try { params[0].configureDevice(username, deviceStr, captionStr, GpodnetDevice.DeviceType.MOBILE); return new GpodnetDevice(deviceStr, captionStr, GpodnetDevice.DeviceType.MOBILE.toString(), 0); } catch (GpodnetServiceException e) { e.printStackTrace(); exception = e; } return null; } }.execute(service); } } }); chooseDevice.setOnClickListener(v -> { final int position = spinnerDevices.getSelectedItemPosition(); if (position != AdapterView.INVALID_POSITION) { selectedDevice = devices.get().get(position); advance(); } }); } private String generateDeviceID(List<GpodnetDevice> gpodnetDevices) { // devices names must be of a certain form: // https://gpoddernet.readthedocs.org/en/latest/api/reference/general.html#devices // This is more restrictive than needed, but I think it makes for more readable names. String baseId = Build.MODEL.replaceAll("\\W", ""); String id = baseId; int num = 0; while (isDeviceWithIdInList(id, gpodnetDevices)) { id = baseId + "_" + num; num++; } return id; } private boolean isDeviceWithIdInList(String id, List<GpodnetDevice> gpodnetDevices) { if (gpodnetDevices == null) { return false; } for (GpodnetDevice device : gpodnetDevices) { if (device.getId().equals(id)) { return true; } } return false; } private boolean checkDeviceIDText(EditText deviceID, EditText caption, TextView txtvError, List<GpodnetDevice> devices) { String text = deviceID.getText().toString(); if (text.length() == 0) { txtvError.setText(R.string.gpodnetauth_device_errorEmpty); txtvError.setVisibility(View.VISIBLE); return false; } else if (caption.length() == 0) { txtvError.setText(R.string.gpodnetauth_device_caption_errorEmpty); txtvError.setVisibility(View.VISIBLE); return false; } else { if (devices != null) { if (isDeviceWithIdInList(text, devices)) { txtvError.setText(R.string.gpodnetauth_device_errorAlreadyUsed); txtvError.setVisibility(View.VISIBLE); return false; } txtvError.setVisibility(View.GONE); return true; } return true; } } private void setupFinishView(View view) { final Button sync = (Button) view.findViewById(R.id.butSyncNow); final Button back = (Button) view.findViewById(R.id.butGoMainscreen); sync.setOnClickListener(v -> { GpodnetSyncService.sendSyncIntent(GpodnetAuthenticationActivity.this); finish(); }); back.setOnClickListener(v -> { Intent intent = new Intent(GpodnetAuthenticationActivity.this, MainActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); startActivity(intent); }); } private void writeLoginCredentials() { if (BuildConfig.DEBUG) Log.d(TAG, "Writing login credentials"); GpodnetPreferences.setUsername(username); GpodnetPreferences.setPassword(password); GpodnetPreferences.setDeviceID(selectedDevice.getId()); } private void advance() { if (currentStep < STEP_FINISH) { View view = views[currentStep + 1]; if (currentStep == STEP_DEFAULT) { setupLoginView(view); } else if (currentStep == STEP_LOGIN) { if (username == null || password == null) { throw new IllegalStateException("Username and password must not be null here"); } else { setupDeviceView(view); } } else if (currentStep == STEP_DEVICE) { if (selectedDevice == null) { throw new IllegalStateException("Device must not be null here"); } else { writeLoginCredentials(); setupFinishView(view); } } if (currentStep != STEP_DEFAULT) { viewFlipper.showNext(); } currentStep++; } else { finish(); } } }