comparing android intent objects - android

I have 2 android intent objects that can be persisted as URLs and then rehydrated back into intent objects. I'm wondering what is the most effective way to compare any 2 intent objects to ensure that they end up resolving to the same activity with the same parameters etc. Using intent.filterEquals does this, but it does not include the extras.
Currently my code for the equals method looks like this:
Intent a = Intent.parseUri(this.intentUrl,
Intent.URI_INTENT_SCHEME);
Intent b = Intent.parseUri(other.intentUrl,
Intent.URI_INTENT_SCHEME);
if (a.filterEquals(b)) {
if (a.getExtras() != null && b.getExtras() != null) {
for (String key : a.getExtras().keySet()) {
if (!b.getExtras().containsKey(key)) {
return false;
} else if (!a.getExtras().get(key)
.equals(b.getExtras().get(key))) {
return false;
}
}
}
// all of the extras are the same so return true
return true;
} else { return false; }
But is there a better/cleaner way?

That's probably as good as it gets, at least conceptually. However, I don't think your algorithm covers cases where b has a key that a does not.
I'd get both keySet() values and run an equals() on those, to confirm they both have the same keys. Then, iterate over one and run equals() on the value pair.

Improving upon #aostiles' answer by adding the missing return statement and also conditions to compare arrays in extras:
private boolean intentsAreEqual (Intent a, Intent b)
{
if (a.filterEquals(b)) {
if (a.getExtras() != null && b.getExtras() != null) {
// check if the keysets are the same size
if (a.getExtras().keySet().size() != b.getExtras().keySet().size()) return false;
// compare all of a's extras to b
for (String key : a.getExtras().keySet()) {
if (!b.getExtras().containsKey(key)) {
return false;
}
else if (a.getExtras().get(key).getClass().isArray() && b.getExtras().get(key).getClass().isArray()) {
if (!Arrays.equals((Object[]) a.getExtras().get(key), (Object[]) b.getExtras().get(key))) {
return false;
}
}
else if (!a.getExtras().get(key).equals(b.getExtras().get(key))) {
return false;
}
}
// compare all of b's extras to a
for (String key : b.getExtras().keySet()) {
if (!a.getExtras().containsKey(key)) {
return false;
}
else if (b.getExtras().get(key).getClass().isArray() && a.getExtras().get(key).getClass().isArray()) {
if (!Arrays.equals((Object[]) b.getExtras().get(key), (Object[]) a.getExtras().get(key))) {
return false;
}
}
else if (!b.getExtras().get(key).equals(a.getExtras().get(key))) {
return false;
}
}
return true;
}
if (a.getExtras() == null && b.getExtras() == null)
{
return true;
}
// either a has extras and b doesn't or b has extras and a doesn't
return false;
}
else
{
return false;
}
}

This is pretty much an implementation of what CommonsWare suggested combined with Ben's code but also covers the case where either a has extras and b does not or b has extras and a does not.
private boolean areEqual(Intent a, Intent b) {
if (a.filterEquals(b)) {
if (a.getExtras() != null && b.getExtras() != null) {
// check if the keysets are the same size
if (a.getExtras().keySet().size() != b.getExtras().keySet().size()) return false;
// compare all of a's extras to b
for (String key : a.getExtras().keySet()) {
if (!b.getExtras().containsKey(key)) {
return false;
} else if (!a.getExtras().get(key).equals(b.getExtras().get(key))) {
return false;
}
}
// compare all of b's extras to a
for (String key : b.getExtras().keySet()) {
if (!a.getExtras().containsKey(key)) {
return false;
} else if (!b.getExtras().get(key).equals(a.getExtras().get(key))) {
return false;
}
}
}
if (a.getExtras() == null && b.getExtras() == null) return true;
// either a has extras and b doesn't or b has extras and a doesn't
return false;
} else {
return false;
}
}

Related

PackageManager check of isEphemeralDisabled causes a deadlock on Android 7.1

private boolean isEphemeralAllowed(
Intent intent, List<ResolveInfo> resolvedActivities, int userId,
boolean skipPackageCheck) {
// Short circuit and return early if possible.
if (isEphemeralDisabled()) {
return false;
}
final int callingUser = UserHandle.getCallingUserId();
if (callingUser != UserHandle.USER_SYSTEM) {
return false;
}
if (mEphemeralResolverConnection == null) {
return false;
}
if (intent.getComponent() != null) {
return false;
}
if ((intent.getFlags() & Intent.FLAG_IGNORE_EPHEMERAL) != 0) {
return false;
}
if (!skipPackageCheck && intent.getPackage() != null) {
return false;
}
final boolean isWebUri = hasWebURI(intent);
private boolean isEphemeralDisabled() {
// ephemeral apps have been disabled across the board
if (DISABLE_EPHEMERAL_APPS) {
return true;
}
// system isn't up yet; can't read settings, so, assume no ephemeral apps
if (!mSystemReady) {
return true;
}
// we can't get a content resolver until the system is ready; these checks must happen last
final ContentResolver resolver = mContext.getContentResolver();
if (Global.getInt(resolver, Global.ENABLE_EPHEMERAL_FEATURE, 1) == 0) {
return true;
}
return Secure.getInt(resolver, Secure.WEB_ACTION_ENABLED, 1) == 0;
}
For Android 7.0, DISABLE_EPHEMERAL_APPS default is true
private static final boolean DISABLE_EPHEMERAL_APPS = true;
But in Android 7.1, Google enabled Instant apps support: https://android.googlesource.com/platform/frameworks/base.git/+/7ef97b6624054fff0d712d85336a45eee70bcc3f%5E%21/#F0
for isEphemeralAllowed method, if call resolveIntent, most of intents will call isEphemeralAllowed method, so this will cause PackageManager service user binder call settingProvider, and will probability cause a deadlock.

EditText checking

I'm trying to check an EditText value, but the application crashes.
How can I handle my EditText?
String stra_txt = edit_1.getText().toString();
boolean first = false;
if (stra_txt.equals("1") || stra_txt.equals("0"))
{
first = true;
}
else
{
first = false;
}
if(first = true)
zheg();
else
{System.exit(0);}
this code does not work too:
String stra_txt = edit_1.getText().toString();
if (stra_txt.equals("1") || stra_txt.equals("0"))
{
zheg();
}
else
{
System.exit(0);
}
upd.
I've found solution:
if (edit_1.getText().toString().equals("")){
finish();
}
else
{
zheg();
}
Use try Catch Block its get actual error or app crash
try
{
String stra_txt = edit_1.getText().toString();
boolean first = false;
boolean second = false;
if (stra_txt.equals("1") || stra_txt.equals("0"))
{
first = true;
}
else
{
first = false;
}
if(first = true)
zheg();
else
{System.exit(0);}
}
catch (Exception e)
{
e.printStackTrace();
}
Check whether you have linked your EditText id with XML
EditText edit_1 = (EditText) findViewById(R.id.edit_1);
if you have given this, then there must be a problem with zheg() method.
Please post your logs here.
Try this code
if(edit_1 != null){
String stra_txt = edit_1.getText().toString();
if ((stra_txt.equals("1") || stra_txt.equals("0")){
zheg();
}else{
// System.exit(0);
finish();
}
}
if this prevents your app from getting crashed then probably you may not be initializing the view. Add this line before the above code:
edit_1 = (EditText)findViewById(YOUR_VIEW_ID);

NFC tag(for NfcA) scan works only from the second time

I wrote a custom plugin to read blocks of data from an NfcA(i.e.non-ndef) tag. It seems to work fine , but only after the second scan. I am using Activity intent to derive the "NfcAdapter.EXTRA_TAG" to later use it for reading the values. I am also updating the Intents in onNewIntent(). OnNewIntent gets called after the second scan and after that I get result all the time.But in the first scan onNewIntent does not gets called, hence I end up using the Activity tag that does not have "NfcAdapter.EXTRA_TAG", hence I get null. Please see the my code below.
SE_NfcA.java(my native code for plugin)
#Override
public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
String Result = "";
String TypeOfTalking = "";
if (action.contains("TalkToNFC"))
{
JSONObject arg_object = args.getJSONObject(0);
TypeOfTalking = arg_object.getString("type");
if(TypeOfTalking != "")
{
if (TypeOfTalking.contains("readBlock"))
{
if(TypeOfTalking.contains("#"))
{
try
{
String[] parts = TypeOfTalking.split("#");
int index = Integer.parseInt(parts[1]);
Result = Readblock(cordova.getActivity().getIntent(),(byte)index);
callbackContext.success(Result);
}
catch(Exception e)
{
callbackContext.error("Exception Reading "+ TypeOfTalking + "due to "+ e.toString());
return false;
}
}
}
else
{
return false;
}
}
else
{
return false;
}
}
else
{
return false;
}
return true;
}
#Override
public void onNewIntent(Intent intent) {
ShowAlert("onNewIntent called");
Tag tagFromIntent = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
super.onNewIntent(intent);
getActivity().setIntent(intent);
savedTag = tagFromIntent;
savedIntent = intent;
}
#Override
public void onPause(boolean multitasking) {
Log.d(TAG, "onPause " + getActivity().getIntent());
super.onPause(multitasking);
if (multitasking) {
// nfc can't run in background
stopNfc();
}
}
#Override
public void onResume(boolean multitasking) {
Log.d(TAG, "onResume " + getActivity().getIntent());
super.onResume(multitasking);
startNfc();
}
public String Readblock(Intent Intent,byte block) throws IOException{
byte[] response = new byte[]{};
if(Intent != null)
{
Tag myTag = Intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
if(savedTag != null)
myTag = savedTag;
if(myTag != null)
{
try{
Reader nTagReader = new Reader(myTag);
nTagReader.close();
nTagReader.connect();
nTagReader.SectorSelect(Sector.Sector0);
response = nTagReader.fast_read(block, block);
nTagReader.close();
return ConvertH(response);
}catch(Exception e){
ShowAlert(e.toString());
}
}
else
ShowAlert("myTag is null.");
}
return null;
}
private void createPendingIntent() {
if (pendingIntent == null) {
Activity activity = getActivity();
Intent intent = new Intent(activity, activity.getClass());
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP| Intent.FLAG_ACTIVITY_CLEAR_TOP);
pendingIntent = PendingIntent.getActivity(activity, 0, intent, 0);
}
}
private void startNfc() {
createPendingIntent(); // onResume can call startNfc before execute
getActivity().runOnUiThread(new Runnable() {
public void run() {
NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(getActivity());
if (nfcAdapter != null && !getActivity().isFinishing()) {
try {
nfcAdapter.enableForegroundDispatch(getActivity(), getPendingIntent(), getIntentFilters(), getTechLists());
if (p2pMessage != null) {
nfcAdapter.setNdefPushMessage(p2pMessage, getActivity());
}
} catch (IllegalStateException e) {
// issue 110 - user exits app with home button while nfc is initializing
Log.w(TAG, "Illegal State Exception starting NFC. Assuming application is terminating.");
}
}
}
});
}
private void stopNfc() {
Log.d(TAG, "stopNfc");
getActivity().runOnUiThread(new Runnable() {
public void run() {
NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(getActivity());
if (nfcAdapter != null) {
try {
nfcAdapter.disableForegroundDispatch(getActivity());
} catch (IllegalStateException e) {
// issue 125 - user exits app with back button while nfc
Log.w(TAG, "Illegal State Exception stopping NFC. Assuming application is terminating.");
}
}
}
});
}
private Activity getActivity() {
return this.cordova.getActivity();
}
private PendingIntent getPendingIntent() {
return pendingIntent;
}
private IntentFilter[] getIntentFilters() {
return intentFilters.toArray(new IntentFilter[intentFilters.size()]);
}
private String[][] getTechLists() {
//noinspection ToArrayCallWithZeroLengthArrayArgument
return techLists.toArray(new String[0][0]);
}
}
My index.js file
nfc.addTagDiscoveredListener(
function(nfcEvent){
console.log(nfcEvent.tag.id);
alert(nfcEvent.tag.id);
window.echo("readBlock#88");//call to plugin
},
function() {
alert("Listening for NFC tags.");
},
function() {
alert("NFC activation failed.");
}
);
SE_NfcA.js(plugin interface for interaction b/w index.js and SE_NfcA.java)
window.echo = function(natureOfTalk)
{
alert("Inside JS Interface, arg =" + natureOfTalk);
cordova.exec(function(result){alert("Result is : "+result);},
function(error){alert("Some Error happened : "+ error);},
"SE_NfcA","TalkToNFC",[{"type": natureOfTalk}]);
};
I guess I have messed up with the Intents/Activity Life-Cycle, please help. TIA!
I found a tweak/hack and made it to work.
Before making any call to read or write, I made one dummy Initialize call.
window.echo("Initialize");
window.echo("readBlock#88");//call to plugin to read.
And in the native code of the plugin, on receiving the "Initialize" token I made a startNFC() call.
else if(TypeOfTalking.equalsIgnoreCase("Initialize"))
{
startNfc();
}

How to solve android error which says onClick exceeded 65535 bytes limit

public void onClick(View v) {
//this contains 4,095 if conditions
}
The code is inexecutable because it says:
Multiple markers at this line
-implements android.view.View.OnClickListener.onClick
-The code of method onClick(View) is exceeding the 65535 bytes limit
Can anyone help me solve this one? because i actually need those 4,095 if conditions in my code.
If you want to keep the 4095 if statements then I'd do something like this:
#Override
public void onClick(View v) {
if (! processPart1(v)) {
processPart2(v);
}
}
private boolean processPart1(View v) {
if (q1.isChecked() && !q2.isChecked() && !q3.isChecked() && !q4.isChecked() && !q5.isChecked() && !q6.isChecked() && !q7.isChecked() && !q8.isChecked() && !q9.isChecked() && !q10.isChecked() && !q11.isChecked() && !q12.isChecked()) {
// do your thing
return true;
}
else if (!q1.isChecked() && q2.isChecked() && !q3.isChecked() && !q4.isChecked() && !q5.isChecked() && !q6.isChecked() && !q7.isChecked() && !q8.isChecked() && !q9.isChecked() && !q10.isChecked() && !q11.isChecked() && !q12.isChecked()) {
// do your thing
return true;
}
// more conditions here...
return false;
}
private void processPart2(View v) {
// more conditions
}
However you can implement this much faster and also easier to modularize:
boolean q[] = {q1.isChecked(), q2.isChecked(), q3.isChecked(),
q4.isChecked(), q5.isChecked(), q6.isChecked(),
q7.isChecked(), q8.isChecked(), q9.isChecked(),
q10.isChecked(), q11.isChecked(), q12.isChecked()};
int value = 0;
for (int i = 0, len = q.length; i < len; i++) {
value += (q[i] ? 1 : 0) << i;
}
switch(value) {
case 0: // do your thing
case 1: // do your thing
case 2: // do your thing
// more case statements ...
}
While your code has to go through 2048 if statements in average the code above processes merely 12 values and then jumps directly to the correct case statement. It's also much less error prone and can be split into different methods easily like this:
processValues0To1023(value);
processValues1024To2047(value);
processValues2048To3071(value);
processValues3072To4095(value);
private void processValues0To1023(int value) {
switch(value) {
case 0: // do your thing
// more case statements ...
}
}
private void processValues1024To2047(int value) {
switch(value) {
case 1024: // do your thing
// more case statements ...
}
}
private void processValues2048To3071(int value) {
// ditto
}
private void processValues3072To4095(int value) {
// ditto
}

How to check programmatically if data roaming is enabled/disabled?

I'm trying to check if the user has enabled/disabled data roaming. All I found so far is that you can check whether or not the user is currently IN roaming, using TelephonyManager.isNetworkRoaming() and NetworkInfo.isRoaming(), but they are not what I need.
Based on Nippey's answer, the actual piece of code that worked for me is:
public Boolean isDataRoamingEnabled(Context context) {
try {
// return true or false if data roaming is enabled or not
return Settings.Secure.getInt(context.getContentResolver(), Settings.Secure.DATA_ROAMING) == 1;
}
catch (SettingNotFoundException e) {
// return null if no such settings exist (device with no radio data ?)
return null;
}
}
You can request the state of the Roaming-Switch via
ContentResolver cr = ContentResolver(getCurrentContext());
Settings.Secure.getInt(cr, Settings.Secure.DATA_ROAMING);
See: http://developer.android.com/reference/android/provider/Settings.Secure.html#DATA_ROAMING
public static final Boolean isDataRoamingEnabled(final Context application_context)
{
try
{
if (VERSION.SDK_INT < 17)
{
return (Settings.System.getInt(application_context.getContentResolver(), Settings.Secure.DATA_ROAMING, 0) == 1);
}
return (Settings.Global.getInt(application_context.getContentResolver(), Settings.Global.DATA_ROAMING, 0) == 1);
}
catch (Exception exception)
{
return false;
}
}
Updated function to account for API deprecation. It is now replaced with:
http://developer.android.com/reference/android/provider/Settings.Global.html#DATA_ROAMING
public static boolean IsDataRoamingEnabled(Context context) {
try {
// return true or false if data roaming is enabled or not
return Settings.Global.getInt(context.getContentResolver(), Settings.Global.DATA_ROAMING) == 1;
}
catch (SettingNotFoundException e) {
return false;
}
}

Categories

Resources