package com.thibaudperso.sonycamera.timelapse.ui.connection; import android.Manifest; import android.app.AlertDialog; import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.net.wifi.ScanResult; import android.net.wifi.WifiConfiguration; import android.os.Bundle; import android.os.Handler; import android.preference.PreferenceManager; import android.support.annotation.NonNull; import android.support.design.widget.FloatingActionButton; import android.support.v4.app.ActivityCompat; import android.support.v4.app.Fragment; import android.support.v4.content.ContextCompat; import android.text.Html; import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.AdapterView.OnItemSelectedListener; import android.widget.ArrayAdapter; import android.widget.CheckBox; import android.widget.EditText; import android.widget.ImageView; import android.widget.ListAdapter; import android.widget.ListView; import android.widget.ProgressBar; import android.widget.Spinner; import android.widget.TextView; import android.widget.Toast; import com.thibaudperso.sonycamera.R; import com.thibaudperso.sonycamera.sdk.CameraAPI; import com.thibaudperso.sonycamera.sdk.model.Device; import com.thibaudperso.sonycamera.sdk.model.DeviceManager; import com.thibaudperso.sonycamera.timelapse.TimelapseApplication; import com.thibaudperso.sonycamera.timelapse.control.io.IOHandler; import com.thibaudperso.sonycamera.timelapse.control.io.TestConnectionListener; import com.thibaudperso.sonycamera.timelapse.control.io.WifiHandler; import com.thibaudperso.sonycamera.timelapse.ui.settings.TimelapseSettingsActivity; import java.util.List; public class ConnectionFragment extends Fragment { private static final String PREF_AUTOMATIC_CONTINUE = "pref_auto_continue"; private static final int PERMISSIONS_REQUEST_COARSE_LOCATION = 1; private static final int REQUEST_CODE_NEXT_STEP = 1; private DeviceManager mDeviceManager; private IOHandler mIOHandler; private WifiHandler mWifiHandler; private CameraAPI mCameraAPI; private AlertDialog alertDialogChooseNetworkConnection; private AlertDialog alertDialogChooseNetworkCreation; private AlertDialog alertDialogAskForPassword; private ImageView connectionInfoNetworkState, connectionInfoAPIState; private ProgressBar connectionInfoNetworkStateProgress, connectionInfoAPIStateProgress; private boolean mAutomaticContinue = true; private boolean mDontCheckNextIO = false; private CheckBox connectionAutomaticCheckbox; private FloatingActionButton connectionContinueButton; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); TimelapseApplication application = (TimelapseApplication) getActivity().getApplication(); mDeviceManager = application.getDeviceManager(); mIOHandler = application.getIOHandler(); mWifiHandler = mIOHandler.getWifiHandler(); mCameraAPI = application.getCameraAPI(); final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(application); mAutomaticContinue = preferences.getBoolean(PREF_AUTOMATIC_CONTINUE, mAutomaticContinue); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View viewResult = inflater.inflate(R.layout.fragment_connection, container, false); connectionInfoNetworkState = (ImageView) viewResult.findViewById(R.id.connectionInfoNetworkState); connectionInfoAPIState = (ImageView) viewResult.findViewById(R.id.connectionInfoAPIState); connectionInfoNetworkStateProgress = (ProgressBar) viewResult.findViewById(R.id.connectionInfoNetworkStateProgress); connectionInfoAPIStateProgress = (ProgressBar) viewResult.findViewById(R.id.connectionInfoAPIStateProgress); ((TextView) viewResult.findViewById(R.id.connectionInfoMessage)).setText( Html.fromHtml(getString(R.string.connection_information_message))); /** * Handle Camera spinner */ final Spinner cameraSpinner = (Spinner) viewResult.findViewById(R.id.connectionCameraSpinner); ArrayAdapter<Device> adapter = new ArrayAdapter<>(getActivity(), android.R.layout.simple_list_item_1, mDeviceManager.getDevices()); adapter.sort(Device.COMPARE_BY_DEVICEMODEL); cameraSpinner.setAdapter(adapter); int defaultPosition = adapter.getPosition(mDeviceManager.getSelectedDevice()); cameraSpinner.setSelection(defaultPosition, false); // http://stackoverflow.com/a/9375624/2239938 cameraSpinner.post(new Runnable() { @Override public void run() { cameraSpinner.setOnItemSelectedListener(new OnItemSelectedListener() { @Override public void onItemSelected(AdapterView<?> arg0, View view, int position, long id) { mDeviceManager.setSelectedDevice((Device) cameraSpinner.getItemAtPosition(position)); checkAPIConnection(); } @Override public void onNothingSelected(AdapterView<?> arg0) { } }); } }); /** * Handle Camera Refresh */ viewResult.findViewById(R.id.connectionInfoRefresh).setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { checkIO(); } }); connectionAutomaticCheckbox = ((CheckBox) viewResult.findViewById(R.id.connectionAutomaticCheckbox)); connectionAutomaticCheckbox.setChecked(mAutomaticContinue); connectionContinueButton = (FloatingActionButton) viewResult.findViewById(R.id.connectionSettingsButton); connectionContinueButton.setVisibility(View.GONE); connectionContinueButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { nextStep(); } }); return viewResult; } @Override public void onResume() { super.onResume(); mWifiHandler.addListener(mWifiListener); checkIO(); } @Override public void onPause() { super.onPause(); mWifiHandler.removeListener(mWifiListener); } @Override public void onDestroy() { super.onDestroy(); if (alertDialogChooseNetworkConnection != null) { alertDialogChooseNetworkConnection.cancel(); } if (alertDialogChooseNetworkCreation != null) { alertDialogChooseNetworkCreation.cancel(); } if (alertDialogAskForPassword != null) { alertDialogAskForPassword.cancel(); } } private void checkIO() { if(mDontCheckNextIO) { mDontCheckNextIO = false; return; } if (checkWifi()) { checkAPIConnection(); } } /* * Wifi */ private boolean checkWifi() { if (!mWifiHandler.isConnected()) { wifiError(); String permission = Manifest.permission.ACCESS_COARSE_LOCATION; if (ContextCompat.checkSelfPermission(getContext(), permission) == PackageManager.PERMISSION_GRANTED) { wifiProgress(); mWifiHandler.scanWifiConnections(mWifiScanListener); } else if (!ActivityCompat.shouldShowRequestPermissionRationale(getActivity(), permission)) { AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); builder.setMessage(R.string.connection_permission_message); builder.setPositiveButton(R.string.connection_permission_ok, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, PERMISSIONS_REQUEST_COARSE_LOCATION); } }); builder.setNegativeButton(R.string.connection_permission_cancel, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { Toast.makeText(getContext(), R.string.connection_permission_cancel_message, Toast.LENGTH_LONG).show(); } }); builder.create().show(); } else { requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, PERMISSIONS_REQUEST_COARSE_LOCATION); } return false; } wifiOk(); return true; } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], @NonNull int[] grantResults) { switch (requestCode) { case PERMISSIONS_REQUEST_COARSE_LOCATION: { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { mWifiHandler.scanWifiConnections(mWifiScanListener); } else { Toast.makeText(getContext(), R.string.connection_permission_cancel_message, Toast.LENGTH_LONG).show(); } } } } private WifiHandler.ScanListener mWifiScanListener = new WifiHandler.ScanListener() { @Override public void onWifiScanFinished(List<ScanResult> sonyCameraScanResults, List<WifiConfiguration> knownSonyCameraConfigurations) { /* * No Sony Camera network found in scan */ if (sonyCameraScanResults.size() == 0) { wifiError(); } /* * No Sony Camera network registered on this phone but we found only one in scan */ else if (knownSonyCameraConfigurations.size() == 0 && sonyCameraScanResults.size() == 1) { askForNetworkPasswordThenConnect(sonyCameraScanResults.get(0)); } /* * No Sony Camera network registered on this phone but we found more than one in scan */ else if (knownSonyCameraConfigurations.size() == 0) { selectNetworkForCreation(sonyCameraScanResults); } /* * There is only one Sony Camera known network connected */ else if (knownSonyCameraConfigurations.size() == 1) { mWifiHandler.connectToNetworkId(knownSonyCameraConfigurations.get(0).networkId); } /* * There is more than one Sony Camera known network connected */ else { selectNetworkForConnection(knownSonyCameraConfigurations); } } }; private WifiHandler.Listener mWifiListener = new WifiHandler.Listener() { @Override public void onWifiConnecting(String ssid) { } @Override public void onWifiConnected(String ssid) { wifiOk(); //before checking connection: give the camera some time to adjust to the new connection new Handler().postDelayed(new Runnable() { public void run() { checkAPIConnection(); } }, 300); } @Override public void onWifiDisconnected() { wifiError(); } }; /* * Handle network prompts */ private void askForNetworkPasswordThenConnect(final ScanResult scanResult) { final EditText input = new EditText(getActivity()); input.setGravity(Gravity.CENTER_HORIZONTAL); alertDialogAskForPassword = new AlertDialog.Builder(getActivity()) .setTitle(String.format(getString(R.string.connection_enter_password), scanResult.SSID)) .setView(input) .setOnCancelListener(new DialogInterface.OnCancelListener() { @Override public void onCancel(DialogInterface dialog) { wifiError(); } }) .setPositiveButton(R.string.connection_enter_password_ok, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { String value = input.getText().toString(); mWifiHandler.createIfNeededThenConnectToWifi(scanResult.SSID, value); } }) .setNegativeButton(R.string.connection_enter_password_cancel, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { wifiError(); } }).show(); } private void selectNetworkForCreation(final List<ScanResult> scanResults) { final ListView listView = new ListView(getActivity()); ListAdapter adapter = new ArrayAdapter<ScanResult>(getActivity(), android.R.layout.simple_list_item_1, scanResults) { @NonNull public View getView(int position, View convertView, @NonNull ViewGroup parent) { View view = super.getView(position, convertView, parent); TextView textView = (TextView) view.findViewById(android.R.id.text1); textView.setText((getItem(position)).SSID); return textView; } }; listView.setAdapter(adapter); listView.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, final View view, int position, long id) { ScanResult scanResult = (ScanResult) parent.getItemAtPosition(position); askForNetworkPasswordThenConnect(scanResult); } }); alertDialogChooseNetworkCreation = new AlertDialog.Builder(getActivity()) .setTitle(R.string.connection_choose_network) .setView(listView) .setOnCancelListener(new DialogInterface.OnCancelListener() { @Override public void onCancel(DialogInterface dialog) { wifiError(); } }) .setNegativeButton(R.string.connection_choose_network_cancel, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { wifiError(); } }).show(); } private void selectNetworkForConnection(final List<WifiConfiguration> wifiConfigurations) { final ListView listView = new ListView(getActivity()); ListAdapter adapter = new ArrayAdapter<WifiConfiguration>(getActivity(), android.R.layout.simple_list_item_1, wifiConfigurations) { @NonNull public View getView(int position, View convertView, @NonNull ViewGroup parent) { View view = super.getView(position, convertView, parent); TextView textView = (TextView) view.findViewById(android.R.id.text1); textView.setText((getItem(position)).SSID); return textView; } }; listView.setAdapter(adapter); listView.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, final View view, int position, long id) { WifiConfiguration wc = (WifiConfiguration) parent.getItemAtPosition(position); mWifiHandler.connectToNetworkId(wc.networkId); } }); alertDialogChooseNetworkConnection = new AlertDialog.Builder(getActivity()) .setTitle(R.string.connection_choose_network) .setView(listView) .setOnCancelListener(new DialogInterface.OnCancelListener() { @Override public void onCancel(DialogInterface dialog) { wifiError(); } }) .setNegativeButton(R.string.connection_choose_network_cancel, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { wifiError(); } }).show(); } private void wifiProgress() { apiError(); connectionInfoNetworkState.setVisibility(View.GONE); connectionInfoNetworkStateProgress.setVisibility(View.VISIBLE); } private void wifiError() { apiError(); connectionInfoNetworkStateProgress.setVisibility(View.GONE); connectionInfoNetworkState.setVisibility(View.VISIBLE); connectionInfoNetworkState.setImageResource(R.drawable.error); } private void wifiOk() { connectionInfoNetworkStateProgress.setVisibility(View.GONE); connectionInfoNetworkState.setVisibility(View.VISIBLE); connectionInfoNetworkState.setImageResource(R.drawable.ok); } private boolean mAPITesting = false; private void checkAPIConnection() { if (mAPITesting || !mWifiHandler.isConnected()) { return; } mAPITesting = true; connectionContinueButton.setVisibility(View.GONE); apiProgress(); mCameraAPI.testConnection(new TestConnectionListener() { @Override public void isConnected(final boolean isConnected) { if (isConnected) { mCameraAPI.initialize(); apiOk(); stepFinished(); } else { apiError(); } mAPITesting = false; } }); } private void apiProgress() { connectionInfoAPIState.setVisibility(View.GONE); connectionInfoAPIStateProgress.setVisibility(View.VISIBLE); } private void apiError() { connectionInfoAPIStateProgress.setVisibility(View.GONE); connectionInfoAPIState.setVisibility(View.VISIBLE); connectionInfoAPIState.setImageResource(R.drawable.error); } private void apiOk() { connectionInfoAPIStateProgress.setVisibility(View.GONE); connectionInfoAPIState.setVisibility(View.VISIBLE); connectionInfoAPIState.setImageResource(R.drawable.ok); } private void stepFinished() { if (connectionAutomaticCheckbox.isChecked()) { nextStep(); } else { connectionContinueButton.setVisibility(View.VISIBLE); } } private void nextStep() { Intent intent = new Intent(getContext(), TimelapseSettingsActivity.class); startActivityForResult(intent, REQUEST_CODE_NEXT_STEP); } @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if(requestCode == REQUEST_CODE_NEXT_STEP) { mDontCheckNextIO = true; wifiError(); connectionContinueButton.setVisibility(View.GONE); } } }