/*
HueFragment04
Copyright (c) 2015 NTT DOCOMO,INC.
Released under the MIT license
http://opensource.org/licenses/mit-license.php
*/
package org.deviceconnect.android.deviceplugin.hue.activity.fragment;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.text.Editable;
import android.text.InputFilter;
import android.text.Spanned;
import android.text.TextWatcher;
import android.util.Log;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.InputMethodManager;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import com.philips.lighting.hue.listener.PHLightListener;
import com.philips.lighting.hue.sdk.PHAccessPoint;
import com.philips.lighting.hue.sdk.PHHueSDK;
import com.philips.lighting.hue.sdk.exception.PHHueInvalidAPIException;
import com.philips.lighting.model.PHBridge;
import com.philips.lighting.model.PHBridgeResource;
import com.philips.lighting.model.PHBridgeResourcesCache;
import com.philips.lighting.model.PHHueError;
import com.philips.lighting.model.PHLight;
import org.deviceconnect.android.deviceplugin.hue.BuildConfig;
import org.deviceconnect.android.deviceplugin.hue.R;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* Hue setting fragment (4).
*/
public class HueFragment04 extends Fragment {
/** Hue access point. */
private PHAccessPoint mAccessPoint;
/** List adapter. */
private ListAdapter mListAdapter;
/** Progress dialog. */
private ProgressDialog mProgressBar;
/**
* newInstance.
*
* @param accessPoint Access point.
* @return fragment Fragment instance.
*/
public static HueFragment04 newInstance(final PHAccessPoint accessPoint) {
HueFragment04 fragment = new HueFragment04();
fragment.setPHAccessPoint(accessPoint);
return fragment;
}
/**
* Set PHAccessPoint.
*
* @param accessPoint Access point.
*/
private void setPHAccessPoint(final PHAccessPoint accessPoint) {
mAccessPoint = accessPoint;
}
@Override
public View onCreateView(final LayoutInflater inflater,
final ViewGroup container, final Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.hue_fragment_04, container, false);
PHHueSDK phHueSDK = PHHueSDK.getInstance();
PHBridge bridge = phHueSDK.getSelectedBridge();
if (bridge != null) {
PHBridgeResourcesCache cache = bridge.getResourceCache();
mListAdapter = new ListAdapter(getActivity(), cache.getAllLights());
} else {
mListAdapter = new ListAdapter(getActivity(), new ArrayList<PHLight>());
}
ListView listView = (ListView) view.findViewById(R.id.light_list_view);
listView.setAdapter(mListAdapter);
Button autoBtn = (Button) view.findViewById(R.id.btn_auto_add);
autoBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(final View v) {
searchLightAutomatic();
}
});
Button manualBtn = (Button) view.findViewById(R.id.btn_manual_add);
manualBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(final View v) {
editSerial();
}
});
return view;
}
/**
* Update ListView.
*/
private void updateListView() {
PHHueSDK phHueSDK = PHHueSDK.getInstance();
PHBridge bridge = phHueSDK.getSelectedBridge();
if (bridge != null) {
PHBridgeResourcesCache cache = bridge.getResourceCache();
mListAdapter.setLights(cache.getAllLights());
mListAdapter.notifyDataSetChanged();
}
}
/**
* Edit serial.
*/
private void editSerial() {
final EditText editText = new EditText(getActivity());
editText.setOnKeyListener(new View.OnKeyListener() {
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_DOWN
&& keyCode == KeyEvent.KEYCODE_ENTER) {
InputMethodManager inputMethodManager = (InputMethodManager)
getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
inputMethodManager.hideSoftInputFromWindow(v.getWindowToken(), 0);
return true;
}
return false;
}
});
AlertDialog dialog = new AlertDialog.Builder(getActivity())
.setTitle(R.string.frag04_serial_number_title)
.setMessage(R.string.frag04_serial_number_message)
.setView(editText)
.setPositiveButton(R.string.frag04_serial_ok, new DialogInterface.OnClickListener() {
public void onClick(final DialogInterface dialog, final int whichButton) {
String serial = editText.getText().toString();
searchLightManually(serial);
}
})
.setNegativeButton(R.string.frag04_serial_cancel, new DialogInterface.OnClickListener() {
public void onClick(final DialogInterface dialog, final int whichButton) {
}
})
.show();
final Button positiveButton = dialog.getButton(AlertDialog.BUTTON_POSITIVE);
positiveButton.setEnabled(false);
// Input limit of the serial number
InputFilter inputFilter = new InputFilter() {
@Override
public CharSequence filter(final CharSequence source, final int start, final int end,
final Spanned dest, final int dstart, final int dend) {
if (source.toString().matches("[0-9a-fA-F]+")) {
return source;
} else {
return "";
}
}
};
InputFilter[] filters = new InputFilter[] {
inputFilter, new InputFilter.LengthFilter(6)
};
editText.setFilters(filters);
editText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(final CharSequence s, final int start,
final int count, final int after) {
}
@Override
public void onTextChanged(final CharSequence s, final int start,
final int before, final int count) {
positiveButton.setEnabled(editText.length() == 6);
}
@Override
public void afterTextChanged(final Editable s) {
}
});
editText.setHint(R.string.frag04_serial_number_hint);
}
/**
* Search light automatic.
*/
private void searchLightAutomatic() {
openProgressBar();
PHHueSDK hueSDK = PHHueSDK.getInstance();
PHBridge bridge = hueSDK.getSelectedBridge();
try {
bridge.findNewLights(new PHLightListenerImpl());
} catch (PHHueInvalidAPIException e) {
if (BuildConfig.DEBUG) {
Log.e("Hue", "error", e);
}
closeProgressBar();
}
}
/**
* Search light manually.
*
* @param serial Serial number.
*/
private void searchLightManually(final String serial) {
openProgressBar();
List<String> serials = new ArrayList<String>();
serials.add(serial);
PHHueSDK hueSDK = PHHueSDK.getInstance();
PHBridge bridge = hueSDK.getSelectedBridge();
try {
bridge.findNewLightsWithSerials(serials, new PHLightListenerImpl());
} catch (PHHueInvalidAPIException e) {
if (BuildConfig.DEBUG) {
Log.e("Hue", "error", e);
}
closeProgressBar();
}
}
/**
* UIスレッド上で指定されたRunnableを実行します.
* @param run 実行するRunnable
*/
private void runOnUiThread(final Runnable run) {
final Activity activity = getActivity();
if (activity != null) {
activity.runOnUiThread(run);
}
}
/**
* Open progress bar.
*/
private void openProgressBar() {
runOnUiThread(new Runnable() {
@Override
public void run() {
Activity activity = getActivity();
if (activity != null) {
mProgressBar = new ProgressDialog(activity);
mProgressBar.setProgressStyle(ProgressDialog.STYLE_SPINNER);
mProgressBar.setMessage(getString(R.string.frag04_serial_search));
mProgressBar.setCancelable(false);
mProgressBar.show();
}
}
});
}
/**
* Close progress bar.
*/
private void closeProgressBar() {
runOnUiThread(new Runnable() {
@Override
public void run() {
if (mProgressBar != null) {
mProgressBar.dismiss();
mProgressBar = null;
}
}
});
}
/**
* Show toast.
*
* @param message Show message.
*/
private void showToast(final String message) {
runOnUiThread(new Runnable() {
@Override
public void run() {
Activity activity = getActivity();
if (activity != null) {
Toast.makeText(activity, message, Toast.LENGTH_LONG).show();
}
}
});
}
/**
* 認証に失敗したことを通知するダイアログを表示します.
* <p>
* 通知後に、最初のブリッジ検索画面に遷移します。
* </p>
*/
private void showAuthenticationFailed() {
runOnUiThread(new Runnable() {
@Override
public void run() {
Activity activity = getActivity();
if (activity == null) {
return;
}
new AlertDialog.Builder(activity)
.setTitle(R.string.frag02_failed)
.setMessage(R.string.frag04_unauthorized_bridge)
.setPositiveButton(R.string.hue_dialog_ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(final DialogInterface dialog, final int which) {
moveFirstFragment();
}
})
.setCancelable(false)
.show();
}
});
}
/**
* 最初のフラグメントに移動します.
*/
private void moveFirstFragment() {
FragmentManager manager = getFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
transaction.setCustomAnimations(R.anim.fragment_slide_right_enter, R.anim.fragment_slide_left_exit,
R.anim.fragment_slide_left_enter, R.anim.fragment_slide_right_exit);
transaction.replace(R.id.fragment_frame, new HueFragment01());
transaction.commit();
}
/**
* List adapter class.
*/
private class ListAdapter extends BaseAdapter {
/** Layout inflater. */
private LayoutInflater mInflater;
/** Light list. */
private List<PHLight> mLights;
/**
* Constructor.
*
* @param context Context.
* @param lights Light list.
*/
ListAdapter(final Context context, final List<PHLight> lights) {
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
setLights(lights);
}
@Override
public int getCount() {
return mLights.size();
}
@Override
public Object getItem(final int position) {
return mLights.get(position);
}
@Override
public long getItemId(final int position) {
return position;
}
@SuppressLint("ViewHolder")
@Override
public View getView(final int position, final View convertView, final ViewGroup parent) {
View view = convertView;
if (view == null) {
view = mInflater.inflate(R.layout.hue_access_point, parent, false);
}
PHLight light = mLights.get(position);
TextView titleView = (TextView) view.findViewById(R.id.title);
titleView.setText(light.getName());
return view;
}
/**
* Set lights.
*
* @param lights Light list.
*/
private void setLights(final List<PHLight> lights) {
mLights = lights;
}
}
/**
* Light Listener.
*/
private class PHLightListenerImpl implements PHLightListener {
/** Bridge resource list. */
private final List<PHBridgeResource> mLightHeaders = new ArrayList<PHBridgeResource>();
@Override
public void onError(final int code, final String message) {
closeProgressBar();
if (code == PHHueError.AUTHENTICATION_FAILED) {
showAuthenticationFailed();
} else {
showToast(message);
}
}
@Override
public void onSuccess() {
}
@Override
public void onReceivingLights(final List<PHBridgeResource> lightHeaders) {
for (PHBridgeResource header : lightHeaders) {
boolean duplicated = false;
for (PHBridgeResource cache : mLightHeaders) {
if (cache.getIdentifier().equals(header.getIdentifier())) {
duplicated = true;
break;
}
}
if (!duplicated) {
mLightHeaders.add(header);
}
}
}
@Override
public void onSearchComplete() {
if (mLightHeaders.size() == 0) {
showToast(getString(R.string.frag04_not_found_new_light));
} else {
String message = getString(R.string.frag04_light_result1);
message += mLightHeaders.size() + getString(R.string.frag04_light_result2);
showToast(message);
}
closeProgressBar();
View view = getView();
if (view != null) {
view.postDelayed(new Runnable() {
@Override
public void run() {
updateListView();
}
}, 400);
}
}
@Override
public void onStateUpdate(final Map<String, String> list, final List<PHHueError> error) {
}
@Override
public void onReceivingLightDetails(final PHLight light) {
}
}
}