Android: Search Dialog doesn't appear - java

I'm currently trying to implement a Search in my App. I followed Google's Tutorial but now, when i press the "Search"-Button (on the Device/Emulator), nothing appears. I'm not sure why.
My searchable.xml File:
<?xml version="1.0" encoding="utf-8"?>
<searchable
xmlns:android="http://schemas.android.com/apk/res/android"
android:label="#string/label_search"
android:hint="#string/search_hint"
android:includeInGlobalSearch="true"
>
</searchable>
This is the Android Manifest part for the Search-Activity:
<!-- Search Activity -->
<activity android:name=".SearchNotes">
<intent-filter>
<action android:name="android.intent.action.SEARCH" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<meta-data android:name="android.app.searchable"
android:resource="#xml/searchable" />
</activity>
The Code which populates my ListActivity:
private void searchAndDisplay(String query){
SQLiteDatabase db = db_con.getReadableDatabase();
final Cursor c = db.rawQuery(
"SELECT headline, id as '_id' FROM entry WHERE " +
"(headline LIKE '%?%') OR (content LIKE '%?%') ",
new String[]{query, query});
this.startManagingCursor(c);
final ListAdapter searchAdapter = new SimpleCursorAdapter(
this,
android.R.layout.simple_list_item_2, c,
new String[] {"headline", "_id"},
new int[] {android.R.id.text1, android.R.id.text2});
this.setListAdapter(searchAdapter);
db.close();
}
This doesn't work in the Emulator, neither on my Android-Device.
What am I missing here?

Do you have
<activity android:name=".OtherActivity" ... >
<!-- enable the search dialog to send searches to SearchableActivity -->
<meta-data android:name="android.app.default_searchable"
android:value=".SearchNotes" />
</activity>
inside your Activity tag? It can also be applied to the Application if you so choose.

I am afraid if android:includeInGlobalSearch="true" is causing an issue, since it requires below steps to be implemented. Try removing android:includeInGlobalSearch="true" from searchable.xml and see if it helps
To provide recent queries suggestions, you need to:
Implement a searchable activity, as described in Creating a Search Interface.
Create a content provider that extends SearchRecentSuggestionsProvider and declare it in your application manifest.
Modify the searchable configuration with information about the content provider that provides search suggestions.
Save queries to your content provider each time a search is executed.
Ref: http://developer.android.com/guide/topics/search/adding-recent-query-suggestions.html

Everything appears fine in your code. What you need to do is just after running your application you should click the Menu button in your emulator or on your mobile. This will open the search option. Choose that and you should be able to search.

Related

Can't get NDEF_DISCOVERED action when opening the application with NFC tag

So I programmed an NFC tag to launch my application that I'm currently working on. I used the following service to do that:
https://play.google.com/store/apps/details?id=com.wakdev.wdnfc&hl=en
What I want to do is to switch from one activity to another whenever the NFC tag opens my application.
Under the manifest tag in my AndroidManifest.xml I have:
<uses-permission android:name="android.permission.NFC" />
<uses-sdk android:minSdkVersion="10"/>
<uses-feature android:name="android.hardware.nfc" android:required="true" />
And my MainActivity looks like this:
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
</activity>
Since the NFC tag opens the MainActivity first, I want to see whether it's been opened by NFC. If it has, switch to another activity.
The problem is that getIntent().getAction() always returns android.intent.action.MAIN while I'm expecting android.nfc.action.NDEF_DISCOVERED.
At the moment I'm performing this check (debugging basically) under onResume() method with the following code:
#Override
protected void onResume() {
super.onResume();
System.out.println(getIntent().getAction());
}
And I've tried performing this check under onCreate() and onStart() methods. All of them return android.intent.action.MAIN result while I expect android.nfc.action.NDEF_DISCOVERED.
I'm fresh in Android development and I'm just trying to make this work for a small prototype. Would appreciate if you guys could help me!
Edit: I got it working! I researched this question a lot and I believe that my NFC tag needed some extra data of a text/plain type (I did not specify this mimeType before as well so seems like it's mandatory). I also had put NDEF_DISCOVERED under LAUNCHER category while trying to debug the application and then changed it back to DEFAULT. I'm finally getting my desired results!
getIntent() returns the Intent that was used to create the activity. In your case, that is the home screen launcher Intent.
When you scan the NFC tag, a new Intent will be delivered to that activity. That Intent is passed to an onNewIntent() method that you can override.
Depending on how your activity is being used, you might need to handle both cases:
Where the user launched your app by scanning the NFC tag, so your activity was created with the NDEF Intent
Where the user launched your app by other means before scanning the NFC tag, so your activity was created with some other Intent and you get the NDEF Intent in onNewIntent()

Inculding a soft keyboard in an application

For a research project, I'm developing an android chat application. For this, it is crucial that all users of the application should use the same, modified keyboard.
My question is the following: Is it possible to deliver a soft keyboard like the simple-keyboard (https://github.com/rkkr/simple-keyboard) with the application? Or alternatively, is it possible to force the user to utilize a certain keyboard for the text input?
Thanks in advance.
It isn't possible to force a keyboard in a non rooted phone, since there's a security block. You can however ask the user to select your keyboard as in Robert's answer:
InputMethodManager imeManager = (InputMethodManager) getApplicationContext().getSystemService(INPUT_METHOD_SERVICE);
imeManager.showInputMethodPicker();
And yes, you can add it in your application, you just need to add the keyboard code within your app, take a look a this question to see how to make a keyboard. But the most important part probably is the Manifest, because it is what will make your application show in the input method picker:
Code by Suragch:
<manifest ...>
<application ... >
<activity ... >
...
</activity>
<service
android:name=".MyInputMethodService"
android:label="Keyboard Display Name"
android:permission="android.permission.BIND_INPUT_METHOD">
<intent-filter>
<action android:name="android.view.InputMethod"/>
</intent-filter>
<meta-data
android:name="android.view.im"
android:resource="#xml/method"/>
</service>
</application>
</manifest>

Return to same state of the activity from another activity on pressing back

I have implemented a search feature in Activity_A. On hitting the search query it displays the results in a tabular form. I have made few table cells as clickable. On clicking a cell, Activity_B is launched which displays some more information. But when i go back, my search results are gone. I have been following android official documentation, but its kind of overwhelming for a beginner like me to completely follow.
I want to return to the same state of Activity_A(that is, having the search results in place) after pressing back navigation from Activity_B. Here is a snippet from AndroidManifest.xml file
<!-- The MainActivity (it has no parent activity) -->
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!-- Activity_A: A child of the MainActivity -->
<activity android:name=".Activity_A"
android:parentActivityName=".MainActivity"
android:label="#string/activity_display_message">
<!-- The meta-data tag is required if you support API level 15 and lower -->
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".MainActivity" />
</activity>
<!-- Activity_B: A child of the Activity_A -->
<activity android:name=".Activity_B"
android:parentActivityName=".Activity_A"
android:label="#string/individual_record">
<!-- The meta-data tag is required if you support API level 15 and lower -->
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".Activity_A" />
</activity>
Here is the code snippet for Activity_A where a intent is created and Activity_B is started.
someTextView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent Activity_B = new Intent(Activity_A.this, Activity_B.class);
startActivity(Activity_B);
}
});
Is there a decent way to make this happen?. Although this question might get marked as duplicate as there are many questions targeting the same, but i'm not able to find a correct solution for it.
As you said you're a beginner, It might be worth checking out Fragments if you haven't read up on them yet as they're more recommended than using multiple Activites (depending on your application). The FragmentManager class makes navigating between Fragments really easy too as it also keeps the state of the Fragments for you.

Add to menu using addIntentOptions providing multiple intents for a single activity

I want to use addIntentOptions to drive my menus when ever possible. This seems the cleanest way to provide them. Rather than explicitly detailing activities, simply ask for a menu listing all the activities which are available for my data item.
So I'm trying to put together a context menu for a ListView. It works great. Only problem is that I have an activity that has two intents that consume my data type, and only the first shows up.
The activity in question in AndroidManifest.xml
<activity android:name=".ui.MyActivity" android:label="The title">
<intent-filter android:label="First context label">
<action android:name="com.sample.action.FIRST_ACTION" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.ALTERNATIVE" />
<category android:name="android.intent.category.SELECTED_ALTERNATIVE" />
<data android:scheme="myscheme" />
</intent-filter>
<intent-filter android:label="Second context label">
<action android:name="com.sample.action.SECOND_ACTION" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.ALTERNATIVE" />
<category android:name="android.intent.category.SELECTED_ALTERNATIVE" />
<data android:scheme="myscheme" />
</intent-filter>
</activity>
The code to generate the context menu
#Override
public void onCreateContextMenu(ContextMenu menu, View view,
ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, view, menuInfo);
Uri uri = Uri.fromParts("myscheme", getOpaqueUriOfSelectedItem(view), null)
Intent intent = new Intent(null, uri);
intent.addCategory(Intent.CATEGORY_SELECTED_ALTERNATIVE);
// Search and populate the menu with acceptable offering applications.
menu.addIntentOptions(
0, // Menu group to which new items will be added
0, // Unique item ID (none)
0, // Order for the items (none)
this.getComponentName(), // The current Activity name
null, // Specific items to place first (none)
intent, // Intent created above that describes our requirements
0, // Additional flags to control items (none)
null); // Array of MenuItems that correlate to specific items
// (none)
}
As I say, the first intent of the activity shows up in the context menu and behaves like a dream. But I don't see the second intent, and I see no good reason it shouldn't show up. If Android only allows one intent with a particular category per activity, that's a pretty lame restriction.
I can see myself building a dummy activity that simply hands off to MyActivity. But that's clumsy and I'd like to avoid it if possible.
EDIT: Looking at the intent that is passed through to an activity from a context menu (or option menu, presumably), even if both intents showed up in the menu, the activity wouldn't have enough information to tell which intent was selected, as within the activity getIntent().getAction() is null.
This seems like an unfortunate oversight. Surely it isn't that unusual to have an activity that can consume a type of data in more than one way?
Unless one of you kind folk know something I've missed, it looks like I'm going to be creating my dummy activities.
EDIT: As CommonsWare suggested, I tried using queryIntentActivityOptions. I added in this code before menu.addIntentOptions in my code above.
PackageManager pm = getPackageManager();
final List<ResolveInfo> available =
pm.queryIntentActivityOptions(this.getComponentName(), null, intent, 0);
And in the debugger I found that available didn't include both of the available intents for MyActivity. So the issue isn't within addIntentOptions, it's deeper, within queryIntentActivityOptions somewhere.
My approach cannot work because queryIntentActivityOptions(), and the methods that call it, don't work in the way needed for my approach.
For my approach to work, you would need to get a result per intent-filter matched, which could result in multiple results per activity. Also, you would need to get information about which intent-filter matched in the result, specifically the action of the intent-filter.
However queryIntentActivityOptions() doesn't find intent-filters, it finds activities with at least one matching intent-filter. Meaning you only get one result per activity. The result also provides no information about the intent-filter that matched your intent.
This approach makes sense, but it's a shame that it doesn't allow for an activity to provide multiple ways to consume a particular intent.
So my workaround is to create fake activities for any activity with more than one action, that then hand off to the real activity.
So the sample manifest I included in the question would become
<activity android:name=".ui.MyActivity" android:label="The title" />
<activity android:name=".ui.MyActivityFirstAction" android:label="First action">
<intent-filter android:label="First context label">
<action android:name="com.sample.action.FIRST_ACTION" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.ALTERNATIVE" />
<category android:name="android.intent.category.SELECTED_ALTERNATIVE" />
<data android:scheme="myscheme" />
</intent-filter>
</activity>
<activity android:name=".ui.MyActivitySecondAction" android:label="Second action">
<intent-filter android:label="Second context label">
<action android:name="com.sample.action.SECOND_ACTION" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.ALTERNATIVE" />
<category android:name="android.intent.category.SELECTED_ALTERNATIVE" />
<data android:scheme="myscheme" />
</intent-filter>
</activity>
MyActivityFirstAction and MyActivitySecondAction would simply call MyActivity with the appropriate action and data.
I don't really like this scheme that much, but it still keeps all the actions that are in context menus defined in XML data rather than in code, and allows me to use addIntentOptions().
I still consider addIntentOptions() very tidy, and even if CommonTasks tells me that Google have been backpedaling from it, I will keep using it until I come across issues.
EDIT: As CommonsWare suggests, it would also be possible to create your own library for doing this in a non-hackish fashion. As I end up with more applications, I will probably move in this direction (unless I find an existing method I like better :-) ).

Android homescreen shortcut permission error

In my program it adds a shortcut to the screen. I get the icon on the screen fine, but when I tap it, I get:
03-01 20:00:29.410: ERROR/AndroidRuntime(796): java.lang.SecurityException: Permission Denial: starting Intent { data=http://www.example.com/ flags=0x14000000 comp={com.isaacwaller.example/com.isaacwaller.example.ExampleCut} } from ProcessRecord{435c7398 796:android.process.acore/10005} (pid=796, uid=10005) requires null
Do you know the problem? Thanks,
Isaac
I had something like this happen when I had accidentally duplicated the activity tag for one of my activities in my manifest. I had something like this in my application section.
<activity android:name=".ConventionHome" android:label="#string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="ConventionHome"></activity>
When I removed the second activity tag, things started working normally.
Figured it out, added this under <activity> tag of activity:
<intent-filter>
<action android:name="android.intent.action.MAIN"></action>
</intent-filter>
Something like this should work:
<intent-filter>
<action android:name="com.example.Project.Action"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
inside of the Activity declaration in the manifest.
I ran into this problem too, and it turned out it was because the Activity wasn't exposed to other processes. I had to add the android:exported="true" attribute to the activity tag in my manifest.
See http://developer.android.com/guide/topics/manifest/activity-element.html#exported for more information.
I haven't run into this personally but I did do some research and found the following.
Apparently whatever is attempting to invoke your app or if your app has a call to create an intent and start an activity of some intent the UID is not the same.
In ActivityManagerServer.java there are below judgement in it.
int checkComponentPermission(String permission, int pid, int uid, int reqUid)
// If the target requires a specific UID, always fail for others.
if (reqUid >= 0 && uid != reqUid) {
return PackageManager.PERMISSION_DENIED;
}
I'm going to do some testing on this and see if I can reproduce this in a test application and provide any additional feedback.
Make sure you are only trying to invoke publicly exposed activities through any intents.

Categories