How to add pattern lock functionality code in android ?? - android

i have gone through this link https://code.google.com/p/android-lockpattern/ to apply pattern functionality in my application. But i am facing some issues, I have created continue button to move to next screen for confirming the pattern but its not working at all. I want that when user starts to draw the pattern on the first screen continue button should start working but its not working so. Please tell me the solution.I am attaching my MainActivity.java code.
Thanks in advance
package com.example.lock_pattern;
import com.example.lock_pattern.prefs.DisplayPrefs;
public class MainActivity extends Activity {
private static final String CLASSNAME = MainActivity.class.getName();
public static final String ACTION_CREATE_PATTERN = CLASSNAME
+ ".create_pattern";
public static final String ACTION_COMPARE_PATTERN = CLASSNAME
+ ".compare_pattern";
public static final String ACTION_VERIFY_CAPTCHA = CLASSNAME
+ ".verify_captcha";
* If you use {#link #ACTION_COMPARE_PATTERN} and the user fails to "login"
public static final int RESULT_FAILED = RESULT_FIRST_USER + 1;
* If you use {#link #ACTION_COMPARE_PATTERN} and the user forgot his/ her
public static final int RESULT_FORGOT_PATTERN = RESULT_FIRST_USER + 2;
* If you use {#link #ACTION_COMPARE_PATTERN}, and the user fails to "login"
public static final String EXTRA_RETRY_COUNT = CLASSNAME + ".retry_count";
* Sets value of this key to a theme in {#code R.style.Alp_Theme_*}. Default
public static final String EXTRA_THEME = CLASSNAME + ".theme";
* Key to hold the pattern. It must be a {#code char[]} array.
public static final String EXTRA_PATTERN = CLASSNAME + ".pattern";
* You can provide an {#link ResultReceiver} with this key. The activity
public static final String EXTRA_RESULT_RECEIVER = CLASSNAME
+ ".result_receiver";
* Put a {#link PendingIntent} into this key. It will be sent before
public static final String EXTRA_PENDING_INTENT_OK = CLASSNAME
+ ".pending_intent_ok";
* Put a {#link PendingIntent} into this key. It will be sent before
public static final String EXTRA_PENDING_INTENT_CANCELLED = CLASSNAME
+ ".pending_intent_cancelled";
* You put a {#link Intent} of <i>{#link Activity}</i> into this extra. The
public static final String EXTRA_INTENT_ACTIVITY_FORGOT_PATTERN = CLASSNAME
+ ".intent_activity_forgot_pattern";
* Helper enum for button OK commands. (Because we use only one "OK" button
private static enum ButtonOkCommand {
CONTINUE, FORGOT_PATTERN, DONE
}// ButtonOkCommand
* Delay time to reload the lock pattern view after a wrong pattern.
private static final long DELAY_TIME_TO_RELOAD_LOCK_PATTERN_VIEW = DateUtils.SECOND_IN_MILLIS;
/*
* FIELDS
*/
private int mMaxRetry;
private boolean mAutoSave;
private IEncrypter mEncrypter;
private int mMinWiredDots;
private ButtonOkCommand mBtnOkCmd;
private Intent mIntentResult;
private int mRetryCount = 0;
/*
* CONTROLS
*/
private TextView mTextInfo;
private LockPatternView mLockPatternView;
private View mFooter;
private Button mBtnCancel;
private Button mBtnConfirm;
/**
* Called when the activity is first created.
*/
#Override
public void onCreate(Bundle savedInstanceState) {
if (BuildConfig.DEBUG)
Log.d(CLASSNAME, "ClassName = " + CLASSNAME);
/*
* EXTRA_THEME
*/
if (getIntent().hasExtra(EXTRA_THEME))
setTheme(getIntent().getIntExtra(EXTRA_THEME,
R.style.Alp_Theme_Dark));
super.onCreate(savedInstanceState);
Toast.makeText(getApplicationContext(), "oncreate", 7000).show();
mMinWiredDots = DisplayPrefs.getMinWiredDots(this);
mMaxRetry = DisplayPrefs.getMaxRetry(this);
mAutoSave = SecurityPrefs.isAutoSavePattern(this);
/*
* Encrypter.
*/
char[] encrypterClass = SecurityPrefs.getEncrypterClass(this);
if (encrypterClass != null) {
try {
mEncrypter = (IEncrypter) Class.forName(
new String(encrypterClass), false, getClassLoader())
.newInstance();
} catch (Throwable t) {
throw new InvalidEncrypterException();
}
}
mIntentResult = new Intent();
setResult(RESULT_CANCELED, mIntentResult);
initContentView();
}// onCreate()
#Override
public void onConfigurationChanged(Configuration newConfig) {
Log.d(CLASSNAME, "onConfigurationChanged()");
super.onConfigurationChanged(newConfig);
initContentView();
}// onConfigurationChanged()
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
Toast.makeText(getApplicationContext(), "Inside onKeyDown", Toast.LENGTH_LONG).show();
if (keyCode == KeyEvent.KEYCODE_BACK
&& ACTION_COMPARE_PATTERN.equals(getIntent().getAction())) {
/*
* Use this hook instead of onBackPressed(), because onBackPressed()
* is not available in API 4.
*/
finishWithNegativeResult(RESULT_CANCELED);
return true;
}
return super.onKeyDown(keyCode, event);
}// onKeyDown()
#Override
protected void onDestroy() {
super.onDestroy();
if (BuildConfig.DEBUG)
Log.d(CLASSNAME, "onDestroy()");
}// onDestroy()
/**
* Initializes UI...
*/
private void initContentView() {
/*
* Save all controls' state to restore later.
*/
CharSequence infoText = mTextInfo != null ? mTextInfo.getText() : null;
Boolean btnOkEnabled = mBtnConfirm != null ? mBtnConfirm.isEnabled()
: null;
LockPatternView.DisplayMode lastDisplayMode = mLockPatternView != null ? mLockPatternView
.getDisplayMode() : null;
List<Cell> lastPattern = mLockPatternView != null ? mLockPatternView
.getPattern() : null;
setContentView(R.layout.activity_main);
UI.adjustDialogSizeForLargeScreen(getWindow());
mTextInfo = (TextView) findViewById(R.id.alp_textview_info);
mLockPatternView = (LockPatternView) findViewById(R.id.alp_view_lock_pattern);
mFooter = findViewById(R.id.alp_viewgroup_footer);
mBtnCancel = (Button) findViewById(R.id.alp_button_cancel);
mBtnConfirm = (Button) findViewById(R.id.alp_button_confirm);
/*
* LOCK PATTERN VIEW
*/
if (getResources().getBoolean(R.bool.alp_is_large_screen)) {
int size = getResources().getDimensionPixelSize(
R.dimen.alp_lockpatternview_size);
LayoutParams lp = mLockPatternView.getLayoutParams();
lp.width = size;
lp.height = size;
mLockPatternView.setLayoutParams(lp);
}
/*
* Haptic feedback.
*/
boolean hapticFeedbackEnabled = false;
try {
hapticFeedbackEnabled = Settings.System.getInt(
getContentResolver(),
Settings.System.HAPTIC_FEEDBACK_ENABLED, 0) != 0;
} catch (Throwable t) {
/*
* Ignore it.
*/
}
mLockPatternView.setTactileFeedbackEnabled(hapticFeedbackEnabled);
mLockPatternView.setInStealthMode(DisplayPrefs.isStealthMode(this)
&& !ACTION_VERIFY_CAPTCHA.equals(getIntent().getAction()));
mLockPatternView.setOnPatternListener(mLockPatternViewListener);
if (lastPattern != null && lastDisplayMode != null
&& !ACTION_VERIFY_CAPTCHA.equals(getIntent().getAction()))
mLockPatternView.setPattern(lastDisplayMode, lastPattern);
/*
* COMMAND BUTTONS
*/
if (ACTION_CREATE_PATTERN.equals(getIntent().getAction())) {
Toast.makeText(getApplicationContext(), "initContentView", 7000).show();
mBtnCancel.setOnClickListener(mBtnCancelOnClickListener);
mBtnConfirm.setOnClickListener(mBtnConfirmOnClickListener);
mBtnCancel.setVisibility(View.VISIBLE);
mBtnConfirm.setVisibility(View.VISIBLE);
mFooter.setVisibility(View.VISIBLE);
if (infoText != null)
mTextInfo.setText(infoText);
else
mTextInfo.setText(R.string.alp_msg_draw_an_unlock_pattern);
/*
* BUTTON OK
*/
if (mBtnOkCmd == null)
mBtnOkCmd = ButtonOkCommand.CONTINUE;
switch (mBtnOkCmd) {
case CONTINUE:
mBtnConfirm.setText(R.string.alp_cmd_continue);
break;
case DONE:
mBtnConfirm.setText(R.string.alp_cmd_confirm);
break;
default:
/*
* Do nothing.
*/
break;
}
if (btnOkEnabled != null)
mBtnConfirm.setEnabled(btnOkEnabled);
}// ACTION_CREATE_PATTERN
else if (ACTION_COMPARE_PATTERN.equals(getIntent().getAction())) {
if (TextUtils.isEmpty(infoText))
mTextInfo.setText(R.string.alp_msg_draw_pattern_to_unlock);
else
mTextInfo.setText(infoText);
if (getIntent().hasExtra(EXTRA_INTENT_ACTIVITY_FORGOT_PATTERN)) {
mBtnConfirm.setOnClickListener(mBtnConfirmOnClickListener);
mBtnConfirm.setText(R.string.alp_cmd_forgot_pattern);
mBtnConfirm.setEnabled(true);
mFooter.setVisibility(View.VISIBLE);
}
}// ACTION_COMPARE_PATTERN
else if (ACTION_VERIFY_CAPTCHA.equals(getIntent().getAction())) {
mTextInfo.setText(R.string.alp_msg_redraw_pattern_to_confirm);
final ArrayList<Cell> pattern;
if (getIntent().hasExtra(EXTRA_PATTERN))
pattern = getIntent()
.getParcelableArrayListExtra(EXTRA_PATTERN);
else
getIntent().putParcelableArrayListExtra(
EXTRA_PATTERN,
pattern = LockPatternUtils
.genCaptchaPattern(DisplayPrefs
.getCaptchaWiredDots(this)));
mLockPatternView.setPattern(DisplayMode.Animate, pattern);
}// ACTION_VERIFY_CAPTCHA
}// initContentView()
* Encodes {#code pattern} to a string.
private char[] encodePattern(List<Cell> pattern) {
* Compares {#code pattern} to the given pattern (
private void doComparePattern(List<Cell> pattern) {
Toast.makeText(getApplicationContext(), "Inside doComparePattern", Toast.LENGTH_LONG).show();
if (pattern == null)
return;
boolean okey = false;
if (ACTION_COMPARE_PATTERN.equals(getIntent().getAction())) {
char[] currentPattern = getIntent()
.getCharArrayExtra(EXTRA_PATTERN);
if (currentPattern == null)
currentPattern = SecurityPrefs.getPattern(this);
okey = Arrays.equals(encodePattern(pattern), currentPattern);
}// ACTION_COMPARE_PATTERN
else if (ACTION_VERIFY_CAPTCHA.equals(getIntent().getAction())) {
final List<Cell> captchaPattern = getIntent()
.getParcelableArrayListExtra(EXTRA_PATTERN);
okey = captchaPattern.size() == pattern.size();
if (okey) {
for (int i = 0; i < captchaPattern.size(); i++) {
if (!captchaPattern.get(i).equals(pattern.get(i))) {
okey = false;
break;
}
}// for
}
}// ACTION_VERIFY_CAPTCHA
if (okey)
finishWithResultOk(null);
else {
mRetryCount++;
mIntentResult.putExtra(EXTRA_RETRY_COUNT, mRetryCount);
if (mRetryCount >= mMaxRetry)
finishWithNegativeResult(RESULT_FAILED);
else {
mLockPatternView.setDisplayMode(DisplayMode.Wrong);
mTextInfo.setText(R.string.alp_msg_try_again);
mLockPatternView.postDelayed(mLockPatternViewReloader,
DELAY_TIME_TO_RELOAD_LOCK_PATTERN_VIEW);
}
}
}// doComparePattern()
/**
* Checks and creates the pattern.
*
* #param pattern
* the current pattern of lock pattern view.
*/
private void doCheckAndCreatePattern(List<Cell> pattern) {
Toast.makeText(getApplicationContext(), "Inside doCheckAndCreatePattern", Toast.LENGTH_LONG).show();
if (pattern.size() < mMinWiredDots) {
mLockPatternView.setDisplayMode(DisplayMode.Wrong);
mTextInfo.setText(getResources().getQuantityString(
R.plurals.alp_pmsg_connect_x_dots, mMinWiredDots,
mMinWiredDots));
mLockPatternView.postDelayed(mLockPatternViewReloader,
DELAY_TIME_TO_RELOAD_LOCK_PATTERN_VIEW);
return;
}
if (getIntent().hasExtra(EXTRA_PATTERN)) {
if (Arrays.equals(getIntent().getCharArrayExtra(EXTRA_PATTERN),
encodePattern(pattern))) {
mTextInfo.setText(R.string.alp_msg_your_new_unlock_pattern);
mBtnConfirm.setEnabled(true);
} else {
mTextInfo.setText(R.string.alp_msg_redraw_pattern_to_confirm);
mBtnConfirm.setEnabled(false);
mLockPatternView.setDisplayMode(DisplayMode.Wrong);
mLockPatternView.postDelayed(mLockPatternViewReloader,
DELAY_TIME_TO_RELOAD_LOCK_PATTERN_VIEW);
}
} else {
getIntent().putExtra(EXTRA_PATTERN, encodePattern(pattern));
mTextInfo.setText(R.string.alp_msg_pattern_recorded);
mBtnConfirm.setEnabled(true);
}
}// doCheckAndCreatePattern()
* Finishes activity with {#link Activity#RESULT_OK}.
private void finishWithResultOk(char[] pattern) {
Toast.makeText(getApplicationContext(), "Inside finishWithResultOk", Toast.LENGTH_LONG).show();
if (ACTION_CREATE_PATTERN.equals(getIntent().getAction()))
mIntentResult.putExtra(EXTRA_PATTERN, pattern);
else {
/*
* If the user was "logging in", minimum try count can not be zero.
*/
mIntentResult.putExtra(EXTRA_RETRY_COUNT, mRetryCount + 1);
}
setResult(RESULT_OK, mIntentResult);
/*
* ResultReceiver
*/
ResultReceiver receiver = getIntent().getParcelableExtra(
EXTRA_RESULT_RECEIVER);
if (receiver != null) {
Bundle bundle = new Bundle();
if (ACTION_CREATE_PATTERN.equals(getIntent().getAction()))
bundle.putCharArray(EXTRA_PATTERN, pattern);
else {
/*
* If the user was "logging in", minimum try count can not be
* zero.
*/
bundle.putInt(EXTRA_RETRY_COUNT, mRetryCount + 1);
}
receiver.send(RESULT_OK, bundle);
}
/*
* PendingIntent
*/
PendingIntent pi = getIntent().getParcelableExtra(
EXTRA_PENDING_INTENT_OK);
if (pi != null) {
try {
pi.send(this, RESULT_OK, mIntentResult);
} catch (Throwable t) {
if (BuildConfig.DEBUG) {
Log.e(CLASSNAME, "Error sending PendingIntent: " + pi);
Log.e(CLASSNAME, ">>> " + t);
t.printStackTrace();
}
}
}
finish();
}// finishWithResultOk()
/**
* Finishes the activity with negative result (
* {#link Activity#RESULT_CANCELED}, {#link #RESULT_FAILED} or
* {#link #RESULT_FORGOT_PATTERN}).
*/
private void finishWithNegativeResult(int resultCode) {
if (ACTION_COMPARE_PATTERN.equals(getIntent().getAction()))
mIntentResult.putExtra(EXTRA_RETRY_COUNT, mRetryCount);
setResult(resultCode, mIntentResult);
/*
* ResultReceiver
*/
ResultReceiver receiver = getIntent().getParcelableExtra(
EXTRA_RESULT_RECEIVER);
if (receiver != null) {
Bundle resultBundle = null;
if (ACTION_COMPARE_PATTERN.equals(getIntent().getAction())) {
resultBundle = new Bundle();
resultBundle.putInt(EXTRA_RETRY_COUNT, mRetryCount);
}
receiver.send(resultCode, resultBundle);
}
/*
* PendingIntent
*/
PendingIntent pi = getIntent().getParcelableExtra(
EXTRA_PENDING_INTENT_CANCELLED);
if (pi != null) {
try {
pi.send(this, resultCode, mIntentResult);
} catch (Throwable t) {
if (BuildConfig.DEBUG) {
Log.e(CLASSNAME, "Error sending PendingIntent: " + pi);
Log.e(CLASSNAME, ">>> " + t);
t.printStackTrace();
}
}
}
finish();
}// finishWithNegativeResult()
/*
* LISTENERS
*/
private final LockPatternView.OnPatternListener mLockPatternViewListener = new LockPatternView.OnPatternListener() {
#Override
public void onPatternStart() {
Toast.makeText(getApplicationContext(), "Inside onPatternStart", Toast.LENGTH_LONG).show();
mLockPatternView.removeCallbacks(mLockPatternViewReloader);
mLockPatternView.setDisplayMode(DisplayMode.Correct);
if (ACTION_CREATE_PATTERN.equals(getIntent().getAction())) {
Toast.makeText(getApplicationContext(), "Inside action create pattern", Toast.LENGTH_LONG).show();
mTextInfo.setText(R.string.alp_msg_release_finger_when_done);
mBtnConfirm.setEnabled(true);
if (mBtnOkCmd == ButtonOkCommand.CONTINUE)
getIntent().removeExtra(EXTRA_PATTERN);
}// ACTION_CREATE_PATTERN
else if (ACTION_COMPARE_PATTERN.equals(getIntent().getAction())) {
mTextInfo.setText(R.string.alp_msg_draw_pattern_to_unlock);
}// ACTION_COMPARE_PATTERN
else if (ACTION_VERIFY_CAPTCHA.equals(getIntent().getAction())) {
mTextInfo.setText(R.string.alp_msg_redraw_pattern_to_confirm);
}// ACTION_VERIFY_CAPTCHA
}// onPatternStart()
#Override
public void onPatternDetected(List<Cell> pattern) {
Toast.makeText(getApplicationContext(), "Inside onPatternDetected", Toast.LENGTH_LONG).show();
if (ACTION_CREATE_PATTERN.equals(getIntent().getAction())) {
doCheckAndCreatePattern(pattern);
}// ACTION_CREATE_PATTERN
else if (ACTION_COMPARE_PATTERN.equals(getIntent().getAction())) {
doComparePattern(pattern);
}// ACTION_COMPARE_PATTERN
else if (ACTION_VERIFY_CAPTCHA.equals(getIntent().getAction())) {
if (!DisplayMode.Animate.equals(mLockPatternView
.getDisplayMode()))
doComparePattern(pattern);
}// ACTION_VERIFY_CAPTCHA
}// onPatternDetected()
#Override
public void onPatternCleared() {
Toast.makeText(getApplicationContext(), "Inside onPatternCleared", Toast.LENGTH_LONG).show();
mLockPatternView.removeCallbacks(mLockPatternViewReloader);
if (ACTION_CREATE_PATTERN.equals(getIntent().getAction())) {
mLockPatternView.setDisplayMode(DisplayMode.Correct);
mBtnConfirm.setEnabled(true);
if (mBtnOkCmd == ButtonOkCommand.CONTINUE) {
getIntent().removeExtra(EXTRA_PATTERN);
mTextInfo.setText(R.string.alp_msg_draw_an_unlock_pattern);
} else
mTextInfo
.setText(R.string.alp_msg_redraw_pattern_to_confirm);
}// ACTION_CREATE_PATTERN
else if (ACTION_COMPARE_PATTERN.equals(getIntent().getAction())) {
mLockPatternView.setDisplayMode(DisplayMode.Correct);
mTextInfo.setText(R.string.alp_msg_draw_pattern_to_unlock);
}// ACTION_COMPARE_PATTERN
else if (ACTION_VERIFY_CAPTCHA.equals(getIntent().getAction())) {
mTextInfo.setText(R.string.alp_msg_redraw_pattern_to_confirm);
List<Cell> pattern = getIntent().getParcelableArrayListExtra(
EXTRA_PATTERN);
mLockPatternView.setPattern(DisplayMode.Animate, pattern);
}// ACTION_VERIFY_CAPTCHA
}// onPatternCleared()
#Override
public void onPatternCellAdded(List<Cell> pattern) {
// TODO Auto-generated method stub
}// onPatternCellAdded()
};// mLockPatternViewListener
private final View.OnClickListener mBtnCancelOnClickListener = new View.OnClickListener() {
#Override
public void onClick(View v) {
finishWithNegativeResult(RESULT_CANCELED);
}// onClick()
};// mBtnCancelOnClickListener
private final View.OnClickListener mBtnConfirmOnClickListener = new View.OnClickListener() {
#Override
public void onClick(View v) {
if (ACTION_CREATE_PATTERN.equals(getIntent().getAction())) {
if (mBtnOkCmd == ButtonOkCommand.CONTINUE) {
mBtnOkCmd = ButtonOkCommand.DONE;
mLockPatternView.clearPattern();
mTextInfo
.setText(R.string.alp_msg_redraw_pattern_to_confirm);
mBtnConfirm.setText(R.string.alp_cmd_confirm);
mBtnConfirm.setEnabled(false);
} else {
final char[] pattern = getIntent().getCharArrayExtra(
EXTRA_PATTERN);
if (mAutoSave)
SecurityPrefs.setPattern(MainActivity.this,
pattern);
finishWithResultOk(pattern);
}
}// ACTION_CREATE_PATTERN
else if (ACTION_COMPARE_PATTERN.equals(getIntent().getAction())) {
/*
* We don't need to verify the extra. First, this button is only
* visible if there is this extra in the intent. Second, it is
* the responsibility of the caller to make sure the extra is an
* Intent of Activity.
*/
startActivity((Intent) getIntent().getParcelableExtra(
EXTRA_INTENT_ACTIVITY_FORGOT_PATTERN));
finishWithNegativeResult(RESULT_FORGOT_PATTERN);
}// ACTION_COMPARE_PATTERN
}// onClick()
};// mBtnConfirmOnClickListener
/**
* This reloads the {#link #mLockPatternView} after a wrong pattern.
*/
private final Runnable mLockPatternViewReloader = new Runnable() {
#Override
public void run() {
mLockPatternView.clearPattern();
mLockPatternViewListener.onPatternCleared();
}// run()
};// mLockPatternViewReloader
}

Your bug is in your initialization in initContentView(). You are setting btnOkEnabled before you've loaded the button into mBtnConfirm.
Move your findViewById() calls to the top of that method and you should be all set.

Related

Calling activity method from fragment showing null pointer exception

I have some methods in MainActivity and trying to access from fragment. But the activity is showing null.
MainActivity.java
public class MainActivity extends AppCompatActivity implements
PermissionResultListener, SwipeRefreshLayout.OnRefreshListener {
public boolean requestPermissionStorage() {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
AlertDialog.Builder alert = new AlertDialog.Builder(this)
.setTitle(getString(R.string.storage_permission_request_title))
.setMessage(getString(R.string.storage_permission_request_summary))
.setNeutralButton(getString(R.string.ok), new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
ActivityCompat.requestPermissions(MainActivity.this,
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
Const.EXTDIR_REQUEST_CODE);
}
})
.setCancelable(false);
alert.create().show();
return false;
}
return true;
}
#TargetApi(23)
public void requestSystemWindowsPermission() {
if (!Settings.canDrawOverlays(this)) {
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
Uri.parse("package:" + getPackageName()));
startActivityForResult(intent, Const.SYSTEM_WINDOWS_CODE);
}
}
#TargetApi(23)
private void setSystemWindowsPermissionResult() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (Settings.canDrawOverlays(this)) {
mPermissionResultListener.onPermissionResult(Const.SYSTEM_WINDOWS_CODE,
new String[]{"System Windows Permission"},
new int[]{PackageManager.PERMISSION_GRANTED});
} else {
mPermissionResultListener.onPermissionResult(Const.SYSTEM_WINDOWS_CODE,
new String[]{"System Windows Permission"},
new int[]{PackageManager.PERMISSION_DENIED});
}
} else {
mPermissionResultListener.onPermissionResult(Const.SYSTEM_WINDOWS_CODE,
new String[]{"System Windows Permission"},
new int[]{PackageManager.PERMISSION_GRANTED});
}
}
public void requestPermissionAudio() {
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.RECORD_AUDIO},
Const.AUDIO_REQUEST_CODE);
}
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case Const.EXTDIR_REQUEST_CODE:
if ((grantResults.length > 0) &&
(grantResults[0] != PackageManager.PERMISSION_GRANTED)) {
Log.d(Const.TAG, "write storage Permission Denied");
fab.setEnabled(false);
} else {
Log.d(Const.TAG, "write storage Permission granted");
createDir();
}
}
if (mPermissionResultListener != null) {
mPermissionResultListener.onPermissionResult(requestCode, permissions, grantResults);
}
}
public void setPermissionResultListener(PermissionResultListener mPermissionResultListener) {
this.mPermissionResultListener = mPermissionResultListener;
}
}
SettingActivity.java
public class SettingActivity extends AppCompatPrefernceActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getFragmentManager().beginTransaction().replace(android.R.id.content, new SettingsPreferenceFragment()).commit();
}
public static class SettingsPreferenceFragment extends PreferenceFragment implements SharedPreferences.OnSharedPreferenceChangeListener
, PermissionResultListener, OnDirectorySelectedListerner {
/**
* SharedPreferences object to read the persisted settings
*/
SharedPreferences prefs;
/**
* ListPreference to choose the recording resolution
*/
private ListPreference res;
/**
* CheckBoxPreference to manage audio recording via mic setting
*/
private CheckBoxPreference recaudio;
/**
* CheckBoxPreference to manage onscreen floating control setting
*/
private CheckBoxPreference floatingControl;
/**
* FolderChooser object to choose the directory where the video has to be saved to.
*/
private FolderChooser dirChooser;
/**
* MainActivity object
*/
private MainActivity activity;
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
activity = (MainActivity) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " Not MainActivity class instance");
}
}
/**
* Initialize various listeners and settings preferences.
*
* #param savedInstanceState default savedInstance bundle sent by Android runtime
*/
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.settings);
setPermissionListener();
String defaultSaveLoc = (new File(Environment
.getExternalStorageDirectory() + File.separator + Const.APPDIR)).getPath();
prefs = getPreferenceScreen().getSharedPreferences();
res = (ListPreference) findPreference(getString(R.string.res_key));
ListPreference fps = (ListPreference) findPreference(getString(R.string.fps_key));
ListPreference bitrate = (ListPreference) findPreference(getString(R.string.bitrate_key));
recaudio = (CheckBoxPreference) findPreference(getString(R.string.audiorec_key));
ListPreference filenameFormat = (ListPreference) findPreference(getString(R.string.filename_key));
EditTextPreference filenamePrefix = (EditTextPreference) findPreference(getString(R.string.fileprefix_key));
dirChooser = (FolderChooser) findPreference(getString(R.string.savelocation_key));
floatingControl = (CheckBoxPreference) findPreference(getString(R.string.preference_floating_control_key));
CheckBoxPreference touchPointer = (CheckBoxPreference) findPreference("touch_pointer");
//Set previously chosen directory as initial directory
dirChooser.setCurrentDir(getValue(getString(R.string.savelocation_key), defaultSaveLoc));
ListPreference theme = (ListPreference) findPreference(getString(R.string.preference_theme_key));
theme.setSummary(theme.getEntry());
//Set the summary of preferences dynamically with user choice or default if no user choice is made
updateScreenAspectRatio();
updateResolution(res);
fps.setSummary(getValue(getString(R.string.fps_key), "30"));
float bps = bitsToMb(Integer.parseInt(getValue(getString(R.string.bitrate_key), "7130317")));
bitrate.setSummary(bps + " Mbps");
dirChooser.setSummary(getValue(getString(R.string.savelocation_key), defaultSaveLoc));
filenameFormat.setSummary(getFileSaveFormat());
filenamePrefix.setSummary(getValue(getString(R.string.fileprefix_key), "recording"));
//If record audio checkbox is checked, check for record audio permission
if (recaudio.isChecked())
requestAudioPermission();
//If floating controls is checked, check for system windows permission
if (floatingControl.isChecked())
requestSystemWindowsPermission();
//set callback for directory change
dirChooser.setOnDirectoryClickedListerner(this);
}
/**
* Updates the summary of resolution settings preference
*
* #param pref object of the resolution ListPreference
*/
private void updateResolution(ListPreference pref) {
pref.setSummary(getValue(getString(R.string.res_key), getNativeRes()));
}
/**
* Method to get the device's native resolution
*
* #return device resolution
*/
private String getNativeRes() {
DisplayMetrics metrics = getRealDisplayMetrics();
return getScreenWidth(metrics) + "x" + getScreenHeight(metrics);
}
/**
* Updates the available resolution based on aspect ratio
*/
private void updateScreenAspectRatio() {
Const.ASPECT_RATIO aspect_ratio = getAspectRatio();
Log.d(Const.TAG, "Aspect ratio: " + aspect_ratio);
CharSequence[] entriesValues = getResolutionEntriesValues(aspect_ratio);
res.setEntries(entriesValues);
res.setEntryValues(entriesValues);
}
/**
* Get resolutions based on the device's aspect ratio
*
* #param aspectRatio {#link com.orpheusdroid.screenrecorder.Const.ASPECT_RATIO} of the device
* #return entries for the resolution
*/
private CharSequence[] getResolutionEntriesValues(Const.ASPECT_RATIO aspectRatio) {
ArrayList<String> entries;
switch (aspectRatio) {
case AR16_9:
entries = buildEntries(R.array.resolutionsArray_16_9);
break;
case AR18_9:
entries = buildEntries(R.array.resolutionValues_18_9);
break;
default:
entries = buildEntries(R.array.resolutionsArray_16_9);
break;
}
String[] entriesArray = new String[entries.size()];
return entries.toArray(entriesArray);
}
/**
* Build resolutions from the arrays.
*
* #param resID resource ID for the resolution array
* #return ArrayList of available resolutions
*/
private ArrayList<String> buildEntries(int resID) {
DisplayMetrics metrics = getRealDisplayMetrics();
int width = getScreenWidth(metrics);
int height = getScreenHeight(metrics);
String nativeRes = width + "x" + height;
ArrayList<String> entries = new ArrayList<>(Arrays.asList(getResources().getStringArray(resID)));
Iterator<String> entriesIterator = entries.iterator();
while (entriesIterator.hasNext()) {
String entry = entriesIterator.next();
String[] widthHeight = entry.split("x");
if (width < Integer.parseInt(widthHeight[0]) || height < Integer.parseInt(widthHeight[1])) {
entriesIterator.remove();
}
}
if (!entries.contains(nativeRes))
entries.add(nativeRes);
return entries;
}
/**
* Returns object of DisplayMetrics
*
* #return DisplayMetrics
*/
private DisplayMetrics getRealDisplayMetrics(){
DisplayMetrics metrics = new DisplayMetrics();
WindowManager window = (WindowManager) getActivity().getSystemService(Context.WINDOW_SERVICE);
window.getDefaultDisplay().getRealMetrics(metrics);
return metrics;
}
/**
* Get width of screen in pixels
*
* #return screen width
*/
private int getScreenWidth(DisplayMetrics metrics) {
return metrics.widthPixels;
}
/**
* Get height of screen in pixels
*
* #return Screen height
*/
private int getScreenHeight(DisplayMetrics metrics) {
return metrics.heightPixels;
}
/**
* Get aspect ratio of the screen
*/
private Const.ASPECT_RATIO getAspectRatio() {
float screen_width = getScreenWidth(getRealDisplayMetrics());
float screen_height = getScreenHeight(getRealDisplayMetrics());
float aspectRatio;
if (screen_width > screen_height) {
aspectRatio = screen_width / screen_height;
} else {
aspectRatio = screen_height / screen_width;
}
return Const.ASPECT_RATIO.valueOf(aspectRatio);
}
/**
* Set permission listener in the {#link MainActivity} to handle permission results
*/
private void setPermissionListener() {
if (getActivity() != null && getActivity() instanceof MainActivity) {
activity = (MainActivity) getActivity();
activity.setPermissionResultListener(this);
}
}
/**
* Get the persisted value for the preference from default sharedPreference
*
* #param key String represnting the sharedpreference key to fetch
* #param defVal String Default value if the preference does not exist
* #return String the persisted preference value or default if not found
*/
private String getValue(String key, String defVal) {
return prefs.getString(key, defVal);
}
/**
* Method to convert bits per second to MB/s
*
* #param bps float bitsPerSecond
* #return float
*/
private float bitsToMb(float bps) {
return bps / (1024 * 1024);
}
//Register for OnSharedPreferenceChangeListener when the fragment resumes
#Override
public void onResume() {
super.onResume();
getPreferenceScreen().getSharedPreferences()
.registerOnSharedPreferenceChangeListener(this);
}
//Unregister for OnSharedPreferenceChangeListener when the fragment pauses
#Override
public void onPause() {
super.onPause();
getPreferenceScreen().getSharedPreferences()
.unregisterOnSharedPreferenceChangeListener(this);
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
}
//When user changes preferences, update the summary accordingly
#Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String s) {
Preference pref = findPreference(s);
if (pref == null) return;
switch (pref.getTitleRes()) {
case R.string.preference_resolution_title:
updateResolution((ListPreference) pref);
break;
case R.string.preference_fps_title:
String fps = String.valueOf(getValue(getString(R.string.fps_key), "30"));
pref.setSummary(fps);
break;
case R.string.preference_bit_title:
float bps = bitsToMb(Integer.parseInt(getValue(getString(R.string.bitrate_key), "7130317")));
pref.setSummary(bps + " Mbps");
break;
case R.string.preference_filename_format_title:
pref.setSummary(getFileSaveFormat());
break;
case R.string.preference_audio_record_title:
requestAudioPermission();
break;
case R.string.preference_filename_prefix_title:
EditTextPreference etp = (EditTextPreference) pref;
etp.setSummary(etp.getText());
ListPreference filename = (ListPreference) findPreference(getString(R.string.filename_key));
filename.setSummary(getFileSaveFormat());
break;
case R.string.preference_floating_control_title:
requestSystemWindowsPermission();
break;
case R.string.preference_show_touch_title:
CheckBoxPreference showTouchCB = (CheckBoxPreference)pref;
if (showTouchCB.isChecked() && !hasPluginInstalled()){
showTouchCB.setChecked(false);
showDownloadAlert();
}
break;
case R.string.preference_crash_reporting_title:
CheckBoxPreference crashReporting = (CheckBoxPreference)pref;
CheckBoxPreference anonymousStats = (CheckBoxPreference) findPreference(getString(R.string.preference_anonymous_statistics_key));
if(!crashReporting.isChecked())
anonymousStats.setChecked(false);
break;
case R.string.preference_anonymous_statistics_title:
break;
case R.string.preference_theme_title:
activity.recreate();
break;
}
}
/**
* show an alert to download the plugin when the plugin is not found
*/
private void showDownloadAlert() {
new AlertDialog.Builder(getActivity())
.setTitle(R.string.alert_plugin_not_found_title)
.setMessage(R.string.alert_plugin_not_found_message)
.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
try {
getActivity().startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=com.orpheusdroid.screencamplugin")));
} catch (android.content.ActivityNotFoundException e) { // if there is no Google Play on device
getActivity().startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://play.google.com/store/apps/details?id=com.orpheusdroid.screencamplugin")));
}
}
})
.setNeutralButton(android.R.string.no, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
}
})
.create().show();
}
/**
* Check if "show touches" plugin is installed.
*
* #return boolean
*/
private boolean hasPluginInstalled(){
PackageManager pm = getActivity().getPackageManager();
try {
pm.getPackageInfo("com.orpheusdroid.screencamplugin",PackageManager.GET_META_DATA);
} catch (PackageManager.NameNotFoundException e) {
Log.d(Const.TAG, "Plugin not installed");
return false;
}
return true;
}
/**
* Method to concat file prefix with dateTime format
*/
public String getFileSaveFormat() {
String filename = prefs.getString(getString(R.string.filename_key), "yyyyMMdd_hhmmss");
String prefix = prefs.getString(getString(R.string.fileprefix_key), "recording");
return prefix + "_" + filename;
}
/**
* Method to request android permission to record audio
*/
public void requestAudioPermission() {
if (activity != null) {
activity.requestPermissionAudio();
}
}
/**
* Method to request android system windows permission to show floating controls
* <p>
* Shown only on devices above api 23 (Marshmallow)
* </p>
*/
private void requestSystemWindowsPermission() {
if (activity != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
activity.requestSystemWindowsPermission();
} else {
Log.d(Const.TAG, "API is < 23");
}
}
/**
* Show snackbar with permission Intent when the user rejects write storage permission
*/
private void showSnackbar() {
Snackbar.make(getActivity().findViewById(R.id.fab), R.string.snackbar_storage_permission_message,
Snackbar.LENGTH_INDEFINITE).setAction(R.string.snackbar_storage_permission_action_enable,
new View.OnClickListener() {
#Override
public void onClick(View v) {
if (activity != null){
activity.requestPermissionStorage();
}
}
}).show();
}
/**
* Show a dialog when the permission to storage is denied by the user during startup
*/
private void showPermissionDeniedDialog(){
new AlertDialog.Builder(activity)
.setTitle(R.string.alert_permission_denied_title)
.setMessage(R.string.alert_permission_denied_message)
.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
if (activity != null){
activity.requestPermissionStorage();
}
}
})
.setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
showSnackbar();
}
})
.setIconAttribute(android.R.attr.alertDialogIcon)
.setCancelable(false)
.create().show();
}
//Permission result callback to process the result of Marshmallow style permission request
#Override
public void onPermissionResult(int requestCode, String[] permissions, int[] grantResults) {
switch (requestCode) {
case Const.EXTDIR_REQUEST_CODE:
if ((grantResults.length > 0) && (grantResults[0] == PackageManager.PERMISSION_DENIED)) {
Log.d(Const.TAG, "Storage permission denied. Requesting again");
dirChooser.setEnabled(false);
showPermissionDeniedDialog();
} else if((grantResults.length > 0) && (grantResults[0] == PackageManager.PERMISSION_GRANTED)){
dirChooser.setEnabled(true);
}
return;
case Const.AUDIO_REQUEST_CODE:
if ((grantResults.length > 0) && (grantResults[0] == PackageManager.PERMISSION_GRANTED)) {
Log.d(Const.TAG, "Record audio permission granted.");
recaudio.setChecked(true);
} else {
Log.d(Const.TAG, "Record audio permission denied");
recaudio.setChecked(false);
}
return;
case Const.SYSTEM_WINDOWS_CODE:
if ((grantResults.length > 0) && (grantResults[0] == PackageManager.PERMISSION_GRANTED)) {
Log.d(Const.TAG, "System Windows permission granted");
floatingControl.setChecked(true);
} else {
Log.d(Const.TAG, "System Windows permission denied");
floatingControl.setChecked(false);
}
default:
Log.d(Const.TAG, "Unknown permission request with request code: " + requestCode);
}
}
#Override
public void onDirectorySelected() {
Log.d(Const.TAG, "In settings fragment");
if (getActivity() != null && getActivity() instanceof MainActivity) {
((MainActivity) getActivity()).onDirectoryChanged();
}
}
}
I am trying to ask runtime permission from fragment using the methods mention in MainActivity. But activity = getActivity() is showing null.
I have tried using onAttach method in fragment, it is also not working showing class cast exception.
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
activity = (MainActivity) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " Not MainActivity class instance");
}
}
as settingActivity is the container of Fragment, you cant get the context from mainactivity unless mainactivity is container of fragment.
Solution - you can make function static or write them in extends Application Class or settingactivity

android PDF rendering issue

I am realizing pdf viewer function using APV library
when I load pdf file using APV library I mentioned, some part of pages are invisible and sometimes not.
Invisible parts are sometimes paragraph and sometimes picture etc. I think it does not depend on object but trial.
Does anyone have similar problem? If anyone knows, please let me know.
I attached 2 picture that have same page, one normal and the other abnormal.
abnormal
normal
public class mPDFActivity extends PdfViewerActivity {
byte[] startSign = {0x31};
byte[] stopSign = {0x32};
public static boolean isPDFPageRunning = false; // bluetoothservice에서 이 activity로 신호 보낼 때 해당 변수 상태 보고 동작(page 넘김) 할지 말지 결정
public int getPreviousPageImageResource() { return R.drawable.left_arrow; }
public int getNextPageImageResource() { return R.drawable.right_arrow; }
public int getZoomInImageResource() { return R.drawable.zoom_in; }
public int getZoomOutImageResource() { return R.drawable.zoom_out; }
public int getPdfPasswordLayoutResource() { return R.layout.pdf_file_password; }
public int getPdfPageNumberResource() { return R.layout.dialog_pagenumber; }
public int getPdfPasswordEditField() { return R.id.etPassword; }
public int getPdfPasswordOkButton() { return R.id.btOK; }
public int getPdfPasswordExitButton() { return R.id.btExit; }
public int getPdfPageNumberEditField() { return R.id.pagenum_edit; }
public int getMenuOpenFile() {return R.drawable.openfile;}
public int getMenuScanBluetooth() {return R.drawable.ic_action_device_access_bluetooth_searching;}
public Handler PDFHandler;
mPDFActivity currentActivity;
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
if(newConfig .orientation == newConfig.ORIENTATION_LANDSCAPE)
{
}else{
}
}
#Override
public void onCreate(Bundle savedInstanceState) {
isPDFPageRunning = true;
super.onCreate(savedInstanceState);
// Get local Bluetooth adapter
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
// If the adapter is null, then Bluetooth is not supported
if (mBluetoothAdapter == null) {
//FragmentActivity activity = getActivity();
Toast.makeText(getApplicationContext(), "Bluetooth is not available", Toast.LENGTH_LONG).show();
this.finish();
}
byte a[] = {(byte)0x01, (byte)0xff};
if(a[1] == -1) {
int re = Conversion.ByteArraytoInteger(a[0], a[1]);
}
Log.d(TAG,"KK");
}
#Override
protected void onPause() {
super.onPause();
SharedPreferences pref = getSharedPreferences("PDF",0);
SharedPreferences.Editor edit = pref.edit();
if(isAlreadyCreated)
{
}else{
}
edit.putFloat(Constants.ZOOM, mZoom);
edit.putInt(Constants.PAGE, mPage);
edit.commit();
}
#Override
protected void onResume() {
isPDFPageRunning = true;
super.onResume();
float zoom;
int page;
SharedPreferences pref = getSharedPreferences(Constants.PDF, 0);
zoom = pref.getFloat(Constants.ZOOM,1);
page = pref.getInt(Constants.PAGE,1);
if(!isAlreadyCreated){
}
}
#Override
protected void onStop() {
isPDFPageRunning = false;
super.onStop();
}
#Override
protected void onDestroy() {
isPDFPageRunning = false;
super.onDestroy();
mChatService.write(stopSign);
if (mChatService != null) {
mChatService.stop();
}
}
private static final String TAG = "BluetoothChatFragment";
// Intent request codes
private static final int REQUEST_CONNECT_DEVICE_SECURE = 1;
private static final int REQUEST_CONNECT_DEVICE_INSECURE = 2;
private static final int REQUEST_ENABLE_BT = 3;
// Layout Views
private ListView mConversationView;
private EditText mOutEditText;
private Button mSendButton;
/**
* Name of the connected device
*/
private String mConnectedDeviceName = null;
/**
* String buffer for outgoing messages
*/
private StringBuffer mOutStringBuffer;
/**
* Local Bluetooth adapter
*/
private BluetoothAdapter mBluetoothAdapter = null;
/**
* Member object for the chat services
*/
//public BluetoothChatService mChatService = null;
public BluetoothChatService mChatService = null;
ArrayAdapter adapter;
int clickCounter=0;
ArrayList listItems=new ArrayList();
private File[] imagelist;
String[] pdflist;
#Override
public void onStart() {
super.onStart();
// If BT is not on, request that it be enabled.
// setupChat() will then be called during onActivityResult
if (!mBluetoothAdapter.isEnabled()) {
Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
// Otherwise, setup the chat session
} else if (mChatService == null) {
setupChat();
}
}
private void setupChat() {
mChatService = new BluetoothChatService(this, mHandler);
// Initialize the buffer for outgoing messages
mOutStringBuffer = new StringBuffer("");
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case REQUEST_CONNECT_DEVICE_SECURE:
// When DeviceListActivity returns with a device to connect
if (resultCode == Activity.RESULT_OK) {
connectDevice(data, true);
//setupChat();
}
break;
case REQUEST_CONNECT_DEVICE_INSECURE:
// When DeviceListActivity returns with a device to connect
if (resultCode == Activity.RESULT_OK) {
connectDevice(data, false);
}
break;
case REQUEST_ENABLE_BT:
// When the request to enable Bluetooth returns
if (resultCode == Activity.RESULT_OK) {
// Bluetooth is now enabled, so set up a chat session
setupChat();
} else {
// User did not enable Bluetooth or an error occurred
Log.d(TAG, "BT not enabled");
Toast.makeText(this, R.string.bt_not_enabled_leaving,
Toast.LENGTH_SHORT).show();
this.finish();
}
}
}
private final Handler mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
//Activity activity = getApplicationContext();
switch (msg.what) {
case Constants.MESSAGE_STATE_CHANGE:
switch (msg.arg1) {
case BluetoothChatService.STATE_CONNECTED:
setStatus(getString(R.string.title_connected_to, mConnectedDeviceName));
break;
case BluetoothChatService.STATE_CONNECTING:
setStatus(getString(R.string.title_connecting));
break;
case BluetoothChatService.STATE_LISTEN:
case BluetoothChatService.STATE_NONE:
setStatus(getString(R.string.title_not_connected));
break;
}
break;
case Constants.MESSAGE_WRITE:
byte[] writeBuf = (byte[]) msg.obj;
// construct a string from the buffer
String writeMessage = new String(writeBuf);
break;
case Constants.MESSAGE_READ:
/*
byte[] readBuf = (byte[]) msg.obj;
// construct a string from the valid bytes in the buffer
String readMessage = new String(readBuf, 0, msg.what);
//Log.i(TAG,readMessage);
//mConversationArrayAdapter.add(mConnectedDeviceName + ": " + readMessage);
int bytes = msg.arg1; // length of read bytes array
String str = Conversion.byteArraytoHexString(readBuf).substring(0, bytes * 2);
str = str.substring(str.indexOf("ff"));
while(str.length() >= 10)
{
String datA = str.substring(2,5);
String datB = str.substring(6,9);
int dat1 = Conversion.hexStringtoInteger(datA);
int dat2 = Conversion.hexStringtoInteger(datB);
//TODO: 데이터 저장 및 신호처리
str = str.substring(10);
}
Log.e("READ","READ : " + str);
*/
//TODO : mPDFActivity로 메시지에 따른 intent 날려
break;
case Constants.MESSAGE_DEVICE_NAME:
// save the connected device's name
mConnectedDeviceName = msg.getData().getString(Constants.DEVICE_NAME);
if (mPDFActivity.this != null) {
Toast.makeText(mPDFActivity.this, "Connected to "
+ mConnectedDeviceName, Toast.LENGTH_SHORT).show();
mChatService.write(startSign);
}
break;
case Constants.MESSAGE_TOAST:
if (mPDFActivity.this != null) {
Toast.makeText(mPDFActivity.this, msg.getData().getString(Constants.TOAST),
Toast.LENGTH_SHORT).show();
}
break;
case Constants.MESSAGE_PREV_PAGE:
prevPage();
break;
case Constants.MESSAGE_NEXT_PAGE:
nextPage();
break;
case Constants.MESSAGE_VIBRATE:
Vibrator vb = (Vibrator)getSystemService(Context.VIBRATOR_SERVICE);
int duration = msg.getData().getInt(Constants.VIBRATE);
vb.vibrate(duration);
break;
}
}
};
/**
* Establish connection with other divice
*
* #param data An {#link Intent} with {#link DeviceListActivity#EXTRA_DEVICE_ADDRESS} extra.
* #param secure Socket Security type - Secure (true) , Insecure (false)
*/
private void connectDevice(Intent data, boolean secure) {
// Get the device MAC address
String address = data.getExtras()
.getString(DeviceListActivity.EXTRA_DEVICE_ADDRESS);
// Get the BluetoothDevice object
BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
// Attempt to connect to the device
mChatService.connect(device, secure);
}
/**
* Updates the status on the action bar.
*
* #param subTitle status
*/
private void setStatus(CharSequence subTitle) {
Activity activity = this;
if (null == activity) {
return;
}
final ActionBar actionBar = activity.getActionBar();
if (null == actionBar) {
return;
}
actionBar.setSubtitle(subTitle);
}
}

Pictures taken after first shot have low lighting

I am taking pics on android 4.4 using code from here [1]: http://www.vogella.com/tutorials/AndroidCamera/article.html "4. Tutorial: Using the camera API" and using Eclipse "Full Screen activity" as template.
The first picture is normal, but after that the subsequent pictures are too dark to be useful.
I searched SO but couldn't fix it. What am I doing wrong here ?
My MainActivity Class
/**
* An example full-screen activity that shows and hides the system UI (i.e.
* status bar and navigation/system bar) with user interaction.
*
* #see SystemUiHider
*/
public class DashboardActivity extends Activity {
static final String DEBUG_TAG = "fsym";
static String fileName = "";
private Camera camera;
private int cameraId = 0;
static long numPics = 1;
private TextView results;
private ImageView displayArea;
float dpHeight, dpWidth;
/**
* Whether or not the system UI should be auto-hidden after
* {#link #AUTO_HIDE_DELAY_MILLIS} milliseconds.
*/
private static final boolean AUTO_HIDE = true;
/**
* If {#link #AUTO_HIDE} is set, the number of milliseconds to wait after
* user interaction before hiding the system UI.
*/
private static final int AUTO_HIDE_DELAY_MILLIS = 3000;
/**
* If set, will toggle the system UI visibility upon interaction. Otherwise,
* will show the system UI visibility upon interaction.
*/
private static final boolean TOGGLE_ON_CLICK = true;
/**
* The flags to pass to {#link SystemUiHider#getInstance}.
*/
private static final int HIDER_FLAGS = SystemUiHider.FLAG_HIDE_NAVIGATION;
/**
* The instance of the {#link SystemUiHider} for this activity.
*/
private SystemUiHider mSystemUiHider;
#Override
protected void onCreate(Bundle savedInstanceState) {
Log.d(DashboardActivity.DEBUG_TAG, "onCreate called");
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_dashboard);
DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
dpHeight = displayMetrics.heightPixels / displayMetrics.density;
dpWidth = displayMetrics.widthPixels / displayMetrics.density;
final View controlsView = findViewById(R.id.fullscreen_content_controls);
final View contentView = findViewById(R.id.fullscreen_content);
results = (TextView) findViewById(R.id.resultTxtBox);
displayArea = (ImageView) findViewById(R.id.imagePanel);
// Set up an instance of SystemUiHider to control the system UI for
// this activity.
mSystemUiHider = SystemUiHider.getInstance(this, contentView, HIDER_FLAGS);
mSystemUiHider.setup();
mSystemUiHider.setOnVisibilityChangeListener(new SystemUiHider.OnVisibilityChangeListener() {
// Cached values.
int mControlsHeight;
int mShortAnimTime;
#Override
#TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2)
public void onVisibilityChange(boolean visible) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
// If the ViewPropertyAnimator API is available
// (Honeycomb MR2 and later), use it to animate the
// in-layout UI controls at the bottom of the
// screen.
if (mControlsHeight == 0) {
mControlsHeight = controlsView.getHeight();
}
if (mShortAnimTime == 0) {
mShortAnimTime = getResources().getInteger(android.R.integer.config_shortAnimTime);
}
controlsView.animate().translationY(visible ? 0 : mControlsHeight).setDuration(mShortAnimTime);
} else {
// If the ViewPropertyAnimator APIs aren't
// available, simply show or hide the in-layout UI
// controls.
controlsView.setVisibility(visible ? View.VISIBLE : View.GONE);
}
if (visible && AUTO_HIDE) {
// Schedule a hide().
delayedHide(AUTO_HIDE_DELAY_MILLIS);
}
}
});
// Set up the user interaction to manually show or hide the system UI.
contentView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (TOGGLE_ON_CLICK) {
mSystemUiHider.toggle();
} else {
mSystemUiHider.show();
}
}
});
// Upon interacting with UI controls, delay any scheduled hide()
// operations to prevent the jarring behavior of controls going away
// while interacting with the UI.
findViewById(R.id.takePicBtn).setOnTouchListener(mDelayHideTouchListener);
results.setOnTouchListener(mDelayHideTouchListener);
// do we have a camera?
if (!getPackageManager()
.hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
Toast.makeText(this, "No camera on this device", Toast.LENGTH_LONG)
.show();
} else {
cameraId = findFrontFacingCamera();
if (cameraId < 0) {
Toast.makeText(this, "No front facing camera found.",
Toast.LENGTH_LONG).show();
} else {
camera = Camera.open(cameraId);
}
}
}
#Override
protected void onPostCreate(Bundle savedInstanceState) {
Log.d(DashboardActivity.DEBUG_TAG, "onPostCreate called");
super.onPostCreate(savedInstanceState);
uiUpdateRunnable.run();
// Trigger the initial hide() shortly after the activity has been
// created, to briefly hint to the user that UI controls
// are available.
delayedHide(100);
}
/**
* Touch listener to use for in-layout UI controls to delay hiding the
* system UI. This is to prevent the jarring behavior of controls going away
* while interacting with activity UI.
*/
View.OnTouchListener mDelayHideTouchListener = new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
if (AUTO_HIDE) {
delayedHide(AUTO_HIDE_DELAY_MILLIS);
}
return false;
}
};
Handler mHideHandler = new Handler();
Runnable mHideRunnable = new Runnable() {
#Override
public void run() {
mSystemUiHider.hide();
}
};
/**
* Schedules a call to hide() in [delay] milliseconds, canceling any
* previously scheduled calls.
*/
private void delayedHide(int delayMillis) {
Log.d(DashboardActivity.DEBUG_TAG, "delayedHide called");
mHideHandler.removeCallbacks(mHideRunnable);
mHideHandler.postDelayed(mHideRunnable, delayMillis);
}
Handler uiUpdatehandler = new Handler();
Runnable uiUpdateRunnable = new Runnable() {
#Override
public void run() {
if (fileName!=null && fileName.trim().length()>0){
displayArea.setImageBitmap(BitmapFactory.decodeFile(fileName));
displayArea.setRotation(-90);
displayArea.setScaleType(ScaleType.CENTER_INSIDE);
}
results.setText("Ratio:"+FaceAnalyzer.measureFace(fileName));
//results.invalidate();
//displayArea.invalidate();
uiUpdatehandler.postDelayed(uiUpdateRunnable,1000);
}
};
public void takePicture(View view){
Log.d(DashboardActivity.DEBUG_TAG, "takePicture called");
camera.takePicture(null, null, new PhotoHandler(getApplicationContext()));
}
public void quitApp(View view){
uiUpdatehandler.removeCallbacks(uiUpdateRunnable);
finish();
System.exit(0);
}
private int findFrontFacingCamera() {
Log.d(DashboardActivity.DEBUG_TAG, "findFrontfacingCamera called");
int cameraId = -1;
// Search for the front facing camera
int numberOfCameras = Camera.getNumberOfCameras();
for (int i = 0; i < numberOfCameras; i++) {
CameraInfo info = new CameraInfo();
Camera.getCameraInfo(i, info);
if (info.facing == CameraInfo.CAMERA_FACING_FRONT) {
Log.d(DEBUG_TAG, "Camera found");
cameraId = i;
break;
}
}
return cameraId;
}
#Override
protected void onPause() {
Log.d(DashboardActivity.DEBUG_TAG, "onPause called");
if (camera != null) {
camera.release();
camera = null;
}
super.onPause();
}
}
My PhotoHandler:
public class PhotoHandler implements PictureCallback {
private final Context context;
public PhotoHandler(Context context) {
Log.d(DashboardActivity.DEBUG_TAG, "Photohandler contstructor called");
this.context = context;
}
#Override
public void onPictureTaken(byte[] data, Camera camera) {
Log.d(DashboardActivity.DEBUG_TAG, "onPicturetaken called");
File pictureFileDir = getDir();
if (!pictureFileDir.exists() && !pictureFileDir.mkdirs()) {
Log.d(DashboardActivity.DEBUG_TAG, "Can't create directory to save image.");
Toast.makeText(context, "Can't create directory to save image.",
Toast.LENGTH_LONG).show();
return;
}
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyymmddhhmmss");
String date = dateFormat.format(new Date());
String photoFile = "Picture_" + date +"_" +DashboardActivity.numPics+".jpg";
String filename = pictureFileDir.getPath() + File.separator + photoFile;
File pictureFile = new File(filename);
try {
FileOutputStream fos = new FileOutputStream(pictureFile);
fos.write(data);
fos.close();
Toast.makeText(context, "New Image saved:" + photoFile,
Toast.LENGTH_LONG).show();
Log.d(DashboardActivity.DEBUG_TAG, "New Image saved:" + photoFile);
DashboardActivity.fileName = filename;
DashboardActivity.numPics++;
} catch (Exception error) {
Log.d(DashboardActivity.DEBUG_TAG, "File" + filename + "not saved: "
+ error.getMessage());
Toast.makeText(context, "Image could not be saved.",
Toast.LENGTH_LONG).show();
}
}
private File getDir() {
Log.d(DashboardActivity.DEBUG_TAG, "getDir called");
File sdDir = Environment
.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
return new File(sdDir, "FacialSymmetryAnalyzer");
}
}
What am I doing wrong here ?

User automatic log in with SaveSharedPreference -- InvocationTarget and NullPointer Exceptions

I am using Androids SaveSharedPreference to allow a user to auto login once they already logged in previously. For a user to gain access, their login information must be sent to my server using webscokets, and once a connection is made they will be able to access their accounts.
In terms of present functionality, the users can log into the app the first time and use all the features. The problem arises as the user closes out, not logs out, and attempts to access again and the error below is thrown and the app crashes:
and then
I have seen that the NullPoint error on line 207 of LoggingIn is at:
result = imService.authenticateUser(
SaveSharedPreference
.getUserName(getApplicationContext()),
SaveSharedPreference
.getPassword(getApplicationContext()));
The remaining code of the class in the onCreate method of the LoggingIn class called once app starts:
protected static final int NOT_CONNECTED_TO_SERVICE = 0;
protected static final int FILL_BOTH_USERNAME_AND_PASSWORD = 1;
public static final String AUTHENTICATION_FAILED = "0";
public static final String FRIEND_LIST = "FRIEND_LIST";
protected static final int MAKE_SURE_USERNAME_AND_PASSWORD_CORRECT = 2;
protected static final int NOT_CONNECTED_TO_NETWORK = 3;
private EditText usernameText;
private EditText passwordText;
private Manager imService;
public static final int SIGN_UP_ID = Menu.FIRST;
public static final int EXIT_APP_ID = Menu.FIRST + 1;
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
// This is called when the connection with the service has been
// established, giving us the service object we can use to
// interact with the service. Because we have bound to a explicit
// service that we know is running in our own process, we can
// cast its IBinder to a concrete class and directly access it.
imService = ((MessagingService.IMBinder) service).getService();
if (imService.isUserAuthenticated() == true) {
// Intent i = new Intent(LoggingIn.this, ListOfFriends.class);
Intent i = new Intent(LoggingIn.this, MainActivity.class);
startActivity(i);
LoggingIn.this.finish();
}
}
public void onServiceDisconnected(ComponentName className) {
// This is called when the connection with the service has been
// unexpectedly disconnected -- that is, its process crashed.
// Because it is running in our same process, we should never
// see this happen.
imService = null;
Toast.makeText(LoggingIn.this, R.string.local_service_stopped,
Toast.LENGTH_SHORT).show();
}
};
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
/*
* Start and bind the imService
*/
startService(new Intent(LoggingIn.this, MessagingService.class));
setContentView(R.layout.loggin_in);
setTitle("Login");
ImageButton loginButton = (ImageButton) findViewById(R.id.button1);
usernameText = (EditText) findViewById(R.id.username);
passwordText = (EditText) findViewById(R.id.password);
// If not logged in already
if (SaveSharedPreference.getUserName(getApplicationContext()).length() == 0) {
loginButton.setOnClickListener(new OnClickListener() {
public void onClick(View arg0) {
if (imService == null) {
Toast.makeText(getApplicationContext(),
R.string.not_connected_to_service,
Toast.LENGTH_LONG).show();
// showDialog(NOT_CONNECTED_TO_SERVICE);
return;
} else if (imService.isNetworkConnected() == false) {
Toast.makeText(getApplicationContext(),
R.string.not_connected_to_network,
Toast.LENGTH_LONG).show();
// showDialog(NOT_CONNECTED_TO_NETWORK);
} else if (usernameText.length() > 0
&& passwordText.length() > 0) {
Thread loginThread = new Thread() {
private Handler handler = new Handler();
#Override
public void run() {
String result = null;
try {
result = imService.authenticateUser(
usernameText.getText().toString(),
passwordText.getText().toString());
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
if (result == null
|| result.equals(AUTHENTICATION_FAILED)) {
/*
* Authenticatin failed, inform the user
*/
handler.post(new Runnable() {
public void run() {
Toast.makeText(
getApplicationContext(),
R.string.make_sure_username_and_password_correct,
Toast.LENGTH_LONG).show();
// showDialog(MAKE_SURE_USERNAME_AND_PASSWORD_CORRECT);
}
});
} else {
/*
* if result not equal to authentication
* failed, result is equal to friend and
* group list of the user 0: is for friends,
* 1: is for groups
*/
handler.post(new Runnable() {
public void run() {
// If log in successful, then save
// username and password to shared
// preferences:
SaveSharedPreference.setUserName(
getApplicationContext(),
usernameText.getText()
.toString());
SaveSharedPreference.setPassword(
getApplicationContext(),
passwordText.getText()
.toString());
Intent i = new Intent(
LoggingIn.this,
MainActivity.class);
startActivity(i);
LoggingIn.this.finish();
}
});
}
}
};
loginThread.start();
} else {
/*
* Username or Password is not filled, alert the user
*/
Toast.makeText(getApplicationContext(),
R.string.fill_both_username_and_password,
Toast.LENGTH_LONG).show();
// showDialog(FILL_BOTH_USERNAME_AND_PASSWORD);
}
}
});
} else {
// If already logged in, pull the information and send to server to
// auto log in
Thread loginThread = new Thread() {
private Handler handler = new Handler();
#Override
public void run() {
String result = null;
try {
result = imService.authenticateUser(
SaveSharedPreference
.getUserName(getApplicationContext()),
SaveSharedPreference
.getPassword(getApplicationContext()));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
if (result == null || result.equals(AUTHENTICATION_FAILED)) {
/*
* Authenticatin failed, inform the user
*/
handler.post(new Runnable() {
public void run() {
Toast.makeText(
getApplicationContext(),
R.string.make_sure_username_and_password_correct,
Toast.LENGTH_LONG).show();
// showDialog(MAKE_SURE_USERNAME_AND_PASSWORD_CORRECT);
}
});
} else {
/*
* if result not equal to authentication failed, result
* is equal to friend and group list of the user 0: is
* for friends, 1: is for groups
*/
handler.post(new Runnable() {
public void run() {
Intent i = new Intent(LoggingIn.this,
MainActivity.class);
startActivity(i);
LoggingIn.this.finish();
}
});
}
}
};
loginThread.start();
}
}
How can I allow the users to automatically login with my service successfully?

Android Mosquitto - Client connection state

I've a MQTT client runnning in Android, and a MQTT Broker in the server. My problem is where we will use the app we have some connections drop so my web app needs to know the current state of the client.
So what we are doing right now is:
1 - The server sends a random number to the clients (each client will receive a different random number)
2 - The android client receives the number and send to a web service
3 - The web service writes in SQL db
4 - The server wait 4 secs to the response from android client and if the random number sent by the server == to the number in the db , the client is connected.
But now the problem is when, multi-users sends the random number the only one that will be write in the db is the last one so it's huge design fault.
In order to fix the only good solution is to get a direct response from the MQTT client and have to be unique per client but i don't know if is possible or if is the best way to go.
Some draw to better understand:
Flow
Here is my android code:
public class MQTTService extends Service implements MqttCallback {
public static final String DEBUG_TAG = "MqttService"; // Debug TAG
private static final String MQTT_THREAD_NAME = "MqttService[" + DEBUG_TAG + "]"; // Handler
// Thread
// ID
private String MQTT_BROKER = ""; // Broker URL
// or IP
// Address
private static final int MQTT_PORT = 1883; // Broker Port
public static final int MQTT_QOS_0 = 0; // QOS Level 0 ( Delivery Once no
// confirmation )
public static final int MQTT_QOS_1 = 1; // QOS Level 1 ( Delivery at least
// Once with confirmation )
public static final int MQTT_QOS_2 = 2; // QOS Level 2 ( Delivery only once
// with confirmation with handshake
// )
private static final int MQTT_KEEP_ALIVE = 30000; // KeepAlive Interval in
// MS
private static final String MQTT_KEEP_ALIVE_TOPIC_FORMAT = "/users/%s/keepalive"; // Topic
// format
// for
// KeepAlives
private static final byte[] MQTT_KEEP_ALIVE_MESSAGE = { 0 }; // Keep Alive
// message
// to send
private static final int MQTT_KEEP_ALIVE_QOS = MQTT_QOS_2; // Default
// Keepalive QOS
private static final boolean MQTT_CLEAN_SESSION = false; // Start a clean
// session?
private static final String MQTT_URL_FORMAT = "tcp://%s:%d"; // URL Format
// normally
// don't
// change
public static final String ACTION_START = DEBUG_TAG + ".START"; // Action
// to
// start
public static final String ACTION_STOP = DEBUG_TAG + ".STOP"; // Action to
// stop
public static final String ACTION_KEEPALIVE = DEBUG_TAG + ".KEEPALIVE"; // Action
// to
// keep
// alive
// used
// by
// alarm
// manager
private static final String ACTION_RECONNECT = DEBUG_TAG + ".RECONNECT"; // Action
// to
// reconnect
// private final String DEVICE_ID_FORMAT = "andr_%s"; // Device ID
// Format, add
// any prefix
// you'd like
// Note: There
// is a 23
// character
// limit you
// will get
// An NPE if you
// go over that
// limit
private boolean mStarted = false; // Is the Client started?
private String user_ID; // Device ID, Secure.ANDROID_ID
private Handler mConnHandler; // Seperate Handler thread for networking
private MqttDefaultFilePersistence mDataStore; // Defaults to FileStore
private MemoryPersistence mMemStore; // On Fail reverts to MemoryStore
private MqttConnectOptions mOpts; // Connection Options
private MqttTopic mKeepAliveTopic; // Instance Variable for Keepalive topic
private MqttClient mClient; // Mqtt Client
private AlarmManager mAlarmManager; // Alarm manager to perform repeating
// tasks
private ConnectivityManager mConnectivityManager; // To check for
// connectivity changes
public static final String TAG_CONNECTED = "CONNECTED";
public static final String TAG_ASSIGNED = "ASSIGNED";
public static final String TAG_REFRESH = "REFRESH";
public String TOPIC_CONNECTED = null;
public String TOPIC_ASSIGNED = null;
public String TOPIC_REFRESH = null;
private Intent intent;
private PendingIntent alarmIntent;
private AppMaintenance appStatus;
/**
* Initializes the DeviceId and most instance variables Including the
* Connection Handler, Datastore, Alarm Manager and ConnectivityManager.
*/
#Override
public void onCreate() {
super.onCreate();
// mDeviceId = String.format(DEVICE_ID_FORMAT,
// Secure.getString(getContentResolver(), Secure.ANDROID_ID));
android.os.Debug.waitForDebugger(); // Debugger
appStatus = (AppMaintenance) getApplicationContext();
ExceptionHandler.register(this, appStatus.getException_URL());
HandlerThread thread = new HandlerThread(MQTT_THREAD_NAME);
thread.start();
mConnHandler = new Handler(thread.getLooper());
try {
mDataStore = new MqttDefaultFilePersistence(getCacheDir().getAbsolutePath());
} catch (Exception e) {
// writeToFile("Exception - onCreate()");
e.printStackTrace();
mDataStore = null;
mMemStore = new MemoryPersistence();
}
mOpts = new MqttConnectOptions();
mOpts.setCleanSession(MQTT_CLEAN_SESSION);
// Do not set keep alive interval on mOpts we keep track of it with
// alarm's
mAlarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
mConnectivityManager = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE);
registerReceiver(mConnectivityReceiver, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
}
/**
* Start MQTT Client
*
* #param Context
* context to start the service with
* #return void
*/
public static void actionStart(Context ctx) {
Intent i = new Intent(ctx, MQTTService.class);
i.setAction(ACTION_START);
ctx.startService(i);
}
/**
* Stop MQTT Client
*
* #param Context
* context to start the service with
* #return void
*/
public static void actionStop(Context ctx) {
Intent i = new Intent(ctx, MQTTService.class);
i.setAction(ACTION_STOP);
ctx.startService(i);
}
/**
* Send a KeepAlive Message
*
* #param Context
* context to start the service with
* #return void
*/
public static void actionKeepalive(Context ctx) {
Intent i = new Intent(ctx, MQTTService.class);
i.setAction(ACTION_KEEPALIVE);
ctx.startService(i);
}
/**
* Service onStartCommand Handles the action passed via the Intent
*
* #return START_REDELIVER_INTENT
*/
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
this.intent = intent;
SharedPreferences myPrefs = getSharedPreferences("UserPreferences", MODE_PRIVATE);
MQTT_BROKER = myPrefs.getString("broker", "");
user_ID = myPrefs.getString("userID", "");
String action = intent.getAction();
TOPIC_CONNECTED = user_ID + "\\" + TAG_CONNECTED;
TOPIC_ASSIGNED = user_ID + "\\" + TAG_ASSIGNED;
TOPIC_REFRESH = user_ID + "\\" + TAG_REFRESH;
Log.i(DEBUG_TAG, "Received action of " + action);
// writeToFile("Received action of " + action);
if (user_ID.isEmpty() || user_ID == null)
action = null;
if (action == null) {
Log.i(DEBUG_TAG, "Starting service with no action\n Probably from a crash");
// writeToFile("Starting service with no action\n Probably from a crash");
Toast.makeText(getApplicationContext(), getString(R.string.mqtt_warning_userid), Toast.LENGTH_LONG).show();
action = null;
} else {
if (action.equals(ACTION_START)) {
Log.i(DEBUG_TAG, "Received ACTION_START");
// writeToFile("Received ACTION_START");
start();
} else if (action.equals(ACTION_STOP)) {
Log.i(DEBUG_TAG, "Received ACTION_STOP");
// writeToFile("Received ACTION_STOP");
stop();
} else if (action.equals(ACTION_KEEPALIVE)) {
Log.i(DEBUG_TAG, "Received ACTION_KEEPALIVE");
// writeToFile("Received ACTION_KEEPALIVE");
keepAlive();
} else if (action.equals(ACTION_RECONNECT)) {
Log.i(DEBUG_TAG, "Received ACTION_RECONNECT");
// writeToFile("Received ACTION_RECONNECT");
reconnectIfNecessary();
}
}
return START_NOT_STICKY;
}
/**
* Attempts connect to the Mqtt Broker and listen for Connectivity changes
* via ConnectivityManager.CONNECTVITIY_ACTION BroadcastReceiver
*/
private synchronized void start() {
if (mStarted) {
Log.i(DEBUG_TAG, "Attempt to start while already started");
// writeToFile("Attempt to start while already started");
return;
}
if (hasScheduledKeepAlives()) {
stopKeepAlives();
}
connect();
}
/**
* Attempts to stop the Mqtt client as well as halting all keep alive
* messages queued in the alarm manager
*/
private synchronized void stop() {
if (!mStarted) {
Log.i(DEBUG_TAG, "Attemt to stop connection that isn't running");
// writeToFile("Attemt to stop connection that isn't running");
return;
}
if (mClient != null) {
mConnHandler.post(new Runnable() {
#Override
public void run() {
try {
mClient.disconnect();
} catch (Exception ex) {
// writeToFile("Exception - stop() ");
ex.printStackTrace();
mClient = null;
mStarted = false;
} finally {
mClient = null;
mStarted = false;
stopKeepAlives();
}
}
});
}
}
/**
* Connects to the broker with the appropriate datastore
*/
private synchronized void connect() {
String url = String.format(Locale.US, MQTT_URL_FORMAT, MQTT_BROKER, MQTT_PORT);
Log.i(DEBUG_TAG, "Connecting with URL: " + url);
// writeToFile("Connecting with URL: " + url);
try {
if (mDataStore != null) {
Log.i(DEBUG_TAG, "Connecting with DataStore");
// writeToFile("Connecting with DataStore");
mClient = new MqttClient(url, user_ID, mDataStore);
} else {
Log.i(DEBUG_TAG, "Connecting with MemStore");
// writeToFile("Connecting with MemStore");
mClient = new MqttClient(url, user_ID, mMemStore);
}
} catch (Exception e) {
// writeToFile("Exception - connect L.343");
e.printStackTrace();
}
mConnHandler.post(new Runnable() {
#Override
public void run() {
try {
mClient.connect(mOpts);
mClient.subscribe(new String[] { TOPIC_CONNECTED, TOPIC_ASSIGNED, TOPIC_REFRESH }, new int[] { MQTT_QOS_0,
MQTT_KEEP_ALIVE_QOS, MQTT_KEEP_ALIVE_QOS });
mClient.setCallback(new MQTTPushCallback(MQTTService.this, intent, user_ID, TOPIC_CONNECTED, TOPIC_ASSIGNED,
TOPIC_REFRESH));
mStarted = true; // Service is now connected
Log.i(DEBUG_TAG, "Successfully connected and subscribed starting keep alives");
// writeToFile("Successfully connected and subscribed starting keep alives");
startKeepAlives();
} catch (Exception e) {
// writeToFile("Exception - connect L.366");
e.printStackTrace();
}
}
});
}
/**
* Schedules keep alives via a PendingIntent in the Alarm Manager
*/
private void startKeepAlives() {
Intent i = new Intent();
i.setClass(this, MQTTService.class);
i.setAction(ACTION_KEEPALIVE);
alarmIntent = PendingIntent.getService(this, 0, i, 0);
mAlarmManager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + MQTT_KEEP_ALIVE, MQTT_KEEP_ALIVE, alarmIntent);
Log.i(DEBUG_TAG, "Started keepAlives sucessfully");
// writeToFile("Started keepAlives sucessfully");
}
/**
* Cancels the Pending Intent in the alarm manager
*/
private void stopKeepAlives() {
if (mAlarmManager != null) {
mAlarmManager.cancel(alarmIntent);
}
}
/**
* Publishes a KeepALive to the topic in the broker
*/
private synchronized void keepAlive() {
// if (isForeground()) {
if (isConnected()) {
try {
sendKeepAlive();
return;
} catch (MqttConnectivityException ex) {
// writeToFile("Exception - KeepAlive() 1");
ex.printStackTrace();
reconnectIfNecessary();
} catch (MqttPersistenceException ex) {
// writeToFile("Exception - KeepAlive() 2");
ex.printStackTrace();
stop();
restartService();
} catch (MqttException ex) {
// writeToFile("Exception - KeepAlive() 3");
ex.printStackTrace();
stop();
restartService();
} catch (Exception ex) {
// writeToFile("Exception - KeepAlive() 4");
ex.printStackTrace();
stop();
restartService();
}
}
}
/**
* Checks the current connectivity and reconnects if it is required.
*/
private synchronized void reconnectIfNecessary() {
if (!mStarted && mClient == null)
start();
}
/**
* Query's the NetworkInfo via ConnectivityManager to return the current
* connected state
*
* #return boolean true if we are connected false otherwise
*/
private boolean isNetworkAvailable() {
NetworkInfo info = mConnectivityManager.getActiveNetworkInfo();
return info == null ? false : info.isConnected();
}
/**
* Verifies the client State with our local connected state
*
* #return true if its a match we are connected false if we aren't connected
*/
private boolean isConnected() {
if (mStarted && mClient != null && !mClient.isConnected()) {
Log.i(DEBUG_TAG, "Mismatch between what we think is connected and what is connected");
// writeToFile("Mismatch between what we think is connected and what is connected");
}
if (mClient != null) {
return mStarted && mClient.isConnected() ? true : false;
}
return false;
}
/**
* Receiver that listens for connectivity changes via ConnectivityManager
*/
private final BroadcastReceiver mConnectivityReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// writeToFile("isNetworkAvailable = " + isNetworkAvailable());
if (isNetworkAvailable() && !mStarted) {
Log.i(DEBUG_TAG, "Connectivity Changed...");
// Intent i = new Intent(context, MQTTService.class);
// i.setAction(ACTION_RECONNECT);
// context.startService(i);
restartService();
} else if (!isNetworkAvailable()) {
stop();
}
}
};
/**
* Sends a Keep Alive message to the specified topic
*
* #see MQTT_KEEP_ALIVE_MESSAGE
* #see MQTT_KEEP_ALIVE_TOPIC_FORMAT
* #return MqttDeliveryToken specified token you can choose to wait for
* completion
*/
private synchronized MqttDeliveryToken sendKeepAlive() throws MqttConnectivityException, MqttPersistenceException, MqttException {
if (!isConnected())
throw new MqttConnectivityException();
if (mKeepAliveTopic == null) {
mKeepAliveTopic = mClient.getTopic(String.format(Locale.US, MQTT_KEEP_ALIVE_TOPIC_FORMAT, user_ID));
}
Log.i(DEBUG_TAG, "Sending Keepalive to " + MQTT_BROKER);
// writeToFile("Sending Keepalive to " + MQTT_BROKER);
MqttMessage message = new MqttMessage(MQTT_KEEP_ALIVE_MESSAGE);
message.setQos(MQTT_KEEP_ALIVE_QOS);
return mKeepAliveTopic.publish(message);
}
/**
* Query's the AlarmManager to check if there is a keep alive currently
* scheduled
*
* #return true if there is currently one scheduled false otherwise
*/
private synchronized boolean hasScheduledKeepAlives() {
Intent i = new Intent();
i.setClass(this, MQTTService.class);
i.setAction(ACTION_KEEPALIVE);
PendingIntent pi = PendingIntent.getBroadcast(this, 0, i, PendingIntent.FLAG_NO_CREATE);
return pi != null ? true : false;
}
#Override
public IBinder onBind(Intent arg0) {
return null;
}
/**
* Connectivity Lost from broker
*/
#Override
public void connectionLost(Throwable arg0) {
stopKeepAlives();
mClient = null;
if (isNetworkAvailable()) {
reconnectIfNecessary();
}
}
/**
* Publish Message Completion
*/
#Override
public void deliveryComplete(IMqttDeliveryToken arg0) {
// TODO Auto-generated method stub
}
/**
* Received Message from broker
*/
#Override
public void messageArrived(String arg0, MqttMessage arg1) throws Exception {
// Log.i(DEBUG_TAG,
// " Topic:\t" + topic.getName() + " Message:\t"
// + new String(message.getPayload()) + " QoS:\t"
// + message.getQos());
}
/**
* MqttConnectivityException Exception class
*/
private class MqttConnectivityException extends Exception {
private static final long serialVersionUID = -7385866796799469420L;
}
#Override
public void onDestroy() {
try {
mClient.unsubscribe(new String[] { TOPIC_CONNECTED, TOPIC_ASSIGNED, TOPIC_REFRESH });
mClient.disconnect(0);
} catch (Exception e) {
// writeToFile("Exception - onDestroy() 1");
e.printStackTrace();
} finally {
new WS_LOGOUT(this).execute(user_ID);
}
}
public void restartService() {
mKeepAliveTopic = null;
actionStart(getApplicationContext()); // restart the service
}
}
What sort of latency can you live with when knowing if the client is disconnected?
You can use the Last Will and Testament feature to publish a value to a topic when the server detects that the MQTT keep alive time has expired with out receiving a ping from the client.
You can set the keep alive time at connection time. But depending on your requirements (battery/network usage) you need to work out what to set it to. If I remember correctly the default is 30 seconds (might be 60)
When your client connects it can set a flag on a persitent topic to say it's online, and the LWT can set this to 0.
e.g.
on connect publish "1" to client/[uniqueid]/online
set the LWT to publish "0" to client/[uniqueid]/online

Categories

Resources