I currently have an Android application that has an intent-filter to receive images from the Gallery. It is important that the images are received in the same order that the user selected them in. This seems to be the default behavior on most devices, however on some devices (so far I've seen this on Motorola's running Android 4.x) the order seems undefined. Does anyone know a way to declare in the intent that the images should be received in order? Or a way once the images are recieved to determine the selected order?
Here is relevant code from the manifest
<activity
android:label="#string/app_name"
android:name=".activities.ImportImagesActivity" >
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="image/*" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEND_MULTIPLE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="image/*" />
</intent-filter>
</activity>
And from ImportImagesActivity
private List<Uri> parseIncomingData() {
List<Uri> uriList = null;
Intent intent = this.getIntent();
if(intent != null) {
String action = intent.getAction();
//Single Image
if (action.equalsIgnoreCase("android.intent.action.SEND")) {
//removed for brevity
}
}
//Multiple Images
else if (action.equalsIgnoreCase("android.intent.action.SEND_MULTIPLE")) {
uriList = intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM);
}
}
//more code - at this point images have been recieved
return uriList;
}
EDIT
To give a little context, let me explain the general flow of the app.
The user opens the Gallery and selects images. They choose to 'Share' them with my app. My application receives a list of Uri's which are then displayed using an internal gallery backed by a custom Adapter class. The images display correctly based on the Uri list, the issue is the order of the List<Uri> is sometimes incorrect. It is important to my users that the images appear in the same order they select them in.
Clarification
When I use the term Gallery I am referring to the built in Android app Gallery.
When I use the term 'Share' I am referring to the the Share button within the Gallery app. This allows the user to select from a list of services such as Facebook, Email, and in this case my app.
For Example
imagine a Gallery with 3 images, displayed in an arbitrary order: A, B, and C. The user selects first C then A then B and chooses to share them with my app. On most phones my list will be correctly ordered {C, A, B}, on offending phones this order seems random.
I cannot use the creation timestamp because the creation time is generally irrelevant to the selection order. Adding custom meta data doesn't help either because I don't know the correct initial order.
My observation is that Android gallery displays images in accordance to their recency.
For the devices where you're unable to determine the order, you can import the images from the gallery and check their creation time. Here's a way to do that. Or you could use a metadata extractor app, many jars can be found.
Now, you could just arrange the images in the order of recency and you should be done.
[EDIT]
I have a question. You said they may be selected in any order, so are they "uploading" it onto a server by "sharing"?
If so, then one way is to check which image was uploaded or if you want the order of selection, you could do this. Edit the metadata of the images, there's bound to be a useless tag, select one and edit it on touch. So, if I select image A it changes to 1 and then I select image B it becomes 2. But if I unselect image A now then image B should become 1. So, you could use nodes here. This is the first in first out (FIFO) method. Upon un-selection, A is thrown out of the list and B replaces it.
Is this what you wanted?
EDIT
Sorry, I don't think you can do this without creating your own gallery. Why don't you just import the android gallery into a grid view in your app?
Yeah, I just faced the same problem right now. I am also using Fedor's lazy loading concept.I am not sure how far this will be helpful and whether this is the right approach. But still it solved the problem for me.
I had to do a little modification in the getView(),
#Override
public View getView(int position, View convertView, ViewGroup parent) {
System.gc();
ImageView view;
if(convertView == null) {
view = new ImageView(context);
view.setScaleType(ImageView.ScaleType.FIT_CENTER);
view.setLayoutParams(new GridView.LayoutParams(screenWidth/4, screenHeight/4));
view.setAdjustViewBounds(false);
view.setPadding(2, 2, 2, 2);
System.gc();
}else {
view = (ImageView) convertView;
}
if(view!=null)
{
imageLoader.DisplayImage(urlList.get(position), view);
notifyDataSetChanged(); //Calling this helped to solve the problem.
}
System.gc();
return view;
}
Related
I'm trying to add my app icon in contact details, to work like a shortcut, i manage to show a title and subtitle but the app icon doesn't appear and i don't understand how to show him and how to add the event to navigate to an specific page after click in the custom cell.
someone can help me?
i have the following code on my contact manager:
public static void addContact(Context context, MyContact contact) {
ContentResolver resolver = context.getContentResolver();
// add condition that you want to check
ContentValues contentValues = new ContentValues();
contentValues.put(ContactsContract.Data.RAW_CONTACT_ID,
Integer.parseInt(contact.id));
contentValues.put(ContactsContract.Data.MIMETYPE,
ContactsContract.CommonDataKinds.Im.CONTENT_ITEM_TYPE);
contentValues.put(ContactsContract.CommonDataKinds.Im.TYPE,
ContactsContract.CommonDataKinds.Im.TYPE_CUSTOM);
contentValues.put(ContactsContract.CommonDataKinds.Im.LABEL, "Title");
contentValues.put(ContactsContract.CommonDataKinds.Im.PROTOCOL,
ContactsContract.CommonDataKinds.Im.PROTOCOL_CUSTOM);
contentValues.put(ContactsContract.CommonDataKinds.Im.CUSTOM_PROTOCOL,
"Title");
contentValues.put(ContactsContract.CommonDataKinds.Im.DATA, "TransferĂȘncia");
ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
ops.add(ContentProviderOperation
.newInsert(ContactsContract.Data.CONTENT_URI)
.withValue(Data.MIMETYPE, MIMETYPE)
.withValues(contentValues).build());
try {
resolver.applyBatch(ContactsContract.AUTHORITY, ops);
} catch (Exception e) {
String ex = e.getMessage();
}
}
`
and the following service on android manifest
<service
android:name="com.[appPackage].SyncService"
android:exported="true" >
<intent-filter>
<action android:name="android.content.SyncAdapter" />
</intent-filter>
<meta-data android:name="android.content.SyncAdapter" android:resource="#xml/syncadapter" />
<meta-data android:name="android.provider.CONTACTS_STRUCTURE" android:resource="#xml/contacts" />
</service>
someone can help me? Thx
First of all, each RawContact on the Contacts DB was synced by a particular app, so if that's not already the case for you, I would suggest you have your app insert its own RawContacts, and not mangle with RawContacts existing on the device, as they can be deleted, edited, reset by the controlling app at any time.
Now to get your app's "actions" displayed on the native contacts app, you need to declare your contacts custom mimetype and related fields, you do this with a special xml file called contacts.xml that you declare in your manifest which maps different DataKinds to Data columns like DATA1, DATA2, etc.
You then need to have an activity to catch the intent that will be fired when the user clicks on your custom row.
You declare the intent in the contacts.xml file as well, and you then need to set a similar intent-filter in your activity's manifest block so Android will know which activity to launch.
Here's official documentation: https://developer.android.com/guide/topics/providers/contacts-provider.html#CustomData & here: https://developer.android.com/guide/topics/providers/contacts-provider.html#SocialStreamDataKind
Here's a tutorial: https://medium.com/#stephen.cty/android-account-sync-adapter-and-contacts-contract-database-983281be4847
Again, try to make sure that the myRawContactId value in that tutorial is pointing to a RawContact your app had created, that will prevent future bugs with Google messing with your custom data rows
I am developing an android based note taking application with categories.I am supposed to create notes shortcuts on home screen. When user click on the shortcut the relevant activity should be open and the specific data should be set in Edit-texts i.e Its title and description.I unable to understand the logic to do that.
I tried all possible solutions that come into my mind. I passed Id of note in shortcut intent but when it launch from shortcut the fields are still empty.
This is my snippet of code to create shortcut:
Function to create shortcut:
private void createShortcutOfActivity() {
Intent shortcutIntent = new Intent(getApplicationContext(),
TextNotes.class);
shortcutIntent.setAction(Intent.ACTION_MAIN);
Intent addIntent = new Intent();
addIntent
.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent);
addIntent.putExtra(Intent.EXTRA_SHORTCUT_NAME, editTitle.getText().toString());
addIntent.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE,
Intent.ShortcutIconResource.fromContext(getApplicationContext(),
R.mipmap.ic_launcher));
addIntent.setAction("com.android.launcher.action.INSTALL_SHORTCUT");
addIntent.putExtra("duplicate", false); //may it's already there so don't duplicate
getApplicationContext().sendBroadcast(addIntent);
}
This function is called when user click on option to create shortcut.
In Menifest use permission:
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
Also add intent filter and exported property in non launching activity:
<activity
android:name=".TextNotes"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.CREATE_SHORTCUT"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
The activity receive data from intent when open a note from another activity:
Intent newInt=getIntent();
isDoubleClicked=newInt.getBooleanExtra("Chk",false);
Cat=newInt.getStringExtra("Category");
Id=newInt.getIntExtra("Id",0);
String title=newInt.getStringExtra("Message");
String description=newInt.getStringExtra("Message2");
check=newInt.getStringExtra("Check");
editTitle.setText(title);
editText.setText(description);
I also tried to use this id in the shortcut intent of the function but having no change in result.
shortcutIntent.putExtra("key_primary",Id);
I want to keep the data when open using shortcut.For example for different note shortcut the rspected data should be set in fields just like in whatsapp the chat shortcuts of different contacts can be craeted . But unfortunately I am unable to understand that how should it be done because everytime I open using shortcut its fields become empty. Where should I pass id and how to set data when it launch from shortcut.
If you use shortcutIntent.putExtra("key_primary",Id); then you need to retrieve it using
Id=newInt.getIntExtra("key_primary",0);
That is the first parameter (key_primary) is the key that is used to identify the specific Intent Extra. Thus, the key value must match the key value used when putting the Intent Extra for a value (other than the default) to be retrieved.
As such coding Id=newInt.getIntExtra("Id",0); without using the matching/paired shortcutIntent.putExtra("Id",Id); will always result in 0 as the Intent Extra doesn't exist so the default value is returned.
I am developing an app for commercial use with a background service that is getting transponder numbers (of animals) from an RFID reader via bluetooth.
After processing the received number I would like to send it to the clipboard and paste it in the focused text field of whatever application is currently in front which in my case is a browser app.
I already found a similar question from 2013 but with no accepted answer by now. All answers to the question just explained how to use ClipboardManager to copy and paste code within the developed application but that has not been meant by the problem as he clarified in a comment.
The simplest scenario that I could imagine is to just simulate a paste action on the android device. I would prefer not to need to install a third party app.
Just to add to Kirill's answer and assuming the app has Accessibility permission,
Create a class extending AccessibilityService and override onAccessibilityEvent method.
public class SampleAccessibilityService extends AccessibilityService {
#Override
public void onAccessibilityEvent(AccessibilityEvent accessibilityEvent) {
AccessibilityNodeInfo source = accessibilityEvent.getSource();
if (source != null) {
AccessibilityNodeInfo rowNode = getRootInActiveWindow();
if (rowNode != null) {
for (int i = 0; i < rowNode.getChildCount(); i++) {
AccessibilityNodeInfo accessibilityNodeInfo = rowNode.getChild(i);
if (accessibilityNodeInfo.isEditable() && accessibilityNodeInfo.isFocused()) {
accessibilityNodeInfo.performAction(AccessibilityNodeInfoCompat.ACTION_PASTE);
return;
}
}
}
}
}
#Override
public void onInterrupt() {
}
}
accessibilityNodeInfo.performAction(AccessibilityNodeInfoCompat.ACTION_PASTE) will paste the text that is copied to clipboard.
Also make sure you have right accessibility configuration.
config.xml
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
android:accessibilityFlags="flagDefault"
android:accessibilityEventTypes="typeViewClicked|typeViewFocused"
android:accessibilityFeedbackType="feedbackGeneric"
android:notificationTimeout="0"
android:canRetrieveWindowContent="true"
android:description="#string/testing" />
Here android:accessibilityEventTypes="typeViewClicked|typeViewFocused" will filter the events to view click or view focus.
You can also the events based on the packages using "android:packageNames" (so that your service won't get called often)
Finally declare the service in manifest,
<service android:name=".SampleAccessibilityService"
android:label="#string/app_name"
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
<intent-filter>
<action android:name="android.accessibilityservice.AccessibilityService"/>
</intent-filter>
<meta-data
android:name="android.accessibilityservice"
android:resource="#xml/config" />
</service>
If you want your app to interact with an app that isn't yours (the browser) you will have to give this app accessibility permissions. those are special kind of permission that allow apps to interact with something that is a bit more senstive.
there are accessibility actions, the one that you are looking for is the
AccessibilityNodeInfoCompat.ACTION_PASTE it allows you to preform a paste into a focused field.
Note that I'd recommend you to replace the browser with a inapp WebView, and inject the values with javascript this will be much more robust solution for your automation. you can find more info on how to run JS on a webview here: How to get return value from javascript in webview of android?
I wrote an Android app with an appwidget.
I want to do this in my code:
if (widget_is_used_by_user)
Is there any way for me to know whether the user placed the widget on the home screen?
If You want to know if the Widget is installed, put som e Log, or whatever You want to do inside onEnabled():
public void onEnabled(Context context){
super(context);
Log.d("WIDGET","WIDGET ENABLED);
}
Also, sometimes it is required to set actions inside the receiver in manifest. I saw some posts about that, but in my widget I also get message without setting action:
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="android.appwidget.action.APPWIDGET_ENABLED" />
<action android:name="android.appwidget.action.APPWIDGET_DELETED" />
<action android:name="android.appwidget.action.APPWIDGET_DISABLED" />
</intent-filter>
If you don't want to keep track of them on your own like Opiatefuchs suggests, unfortunately there's no sure way.
You can query the AppWidgetManager to get a list of available appwidget IDs like this:
ComponentName widgetProvider = new ComponentName(this, "appwidget_class_name");
int[] appWidgetIds = AppWidgetManager.getInstance(this).getAppWidgetIds(widgetProvider);
for (int awId : appWidgetIds) {
// If there is any appwidget on the home screen, its ID should be in the list
}
I'm saying there's no sure way because the problem of phantom appwidget IDs (IDs created by the AppWidgetHost that have no "real" widget present on the home screen) is still a reality, even with recent Android versions.
I am working on making custom launcher in android. I have referred the code of android's Jellybean launcher. now I want to make some modification in this launcher.
What I want : As we know there are default five work-space screens and I want to add custom view in any one of the workspace screen. My xml file should be inflated in any one of the screen.
I have tried many ways to do it but as the default launcher code is very complex still having no luck to finding out way for it.
There is already app named SOHO in Playstore doing exactly what I want. I have add the screenshot for referencing what i want.
Please help me if anyone of you having any idea to do it.
I've the answer for you. You can do it both in Launcher2 and Launcher3 package from (AOSP). Jellybean is using Launcher2 may be. I personally suggest you to go with Launcher3, it has buit-in way to do so.
Launcher3:
create a class that extends the com.android.launcher3.Launcher class and override the necessary methods like so:
public class MyLauncher extends Launcher {
#Override
protected boolean hasCustomContentToLeft() {
return true;
}
#Override
protected void addCustomContentToLeft() {
View customView = getLayoutInflater().inflate(R.layout.custom, null);
CustomContentCallbacks callbacks = new CustomContentCallbacks() {
#Override
public void onShow() {}
#Override
public void onScrollProgressChanged(float progress) {}
#Override
public void onHide() {}
};
addToCustomContentPage(customView, callbacks, "custom view");
}
}
Here R.layout.custom is the custom view that you wanted.
Then in the manifest file change the launcher activity class from Launcher to MyLauncher. And that's it.
Launcher2:
in Workspace.java create the following method:
public void addCustomView(View child){
CellLayout layout = (CellLayout) getChildAt(0);
layout.addView(child);
}
then in Launcher.java, find the following line:
mWorkspace = (Workspace) mDragLayer.findViewById(R.id.workspace);
then paste the following code somewhere after that line:
View child = LayoutInflater.from(this).inflate(R.layout.custom, null);
mWorkspace.addCustomView(child);
If I remember correctly you just need to implement a standard activity which displays a home launcher. In your Manifest.xml you just need to define it like this:
<activity android:name=".YourLauncher" android:label="#string/launcher_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
you can simply add view in default lanucher use code
wm = (WindowManager) getSystemService("window");
params = new LayoutParams();
params.type = LayoutParams.TYPE_PHONE;
params.format = PixelFormat.RGBA_8888;
params.flags = LayoutParams.FLAG_NOT_TOUCH_MODAL
| LayoutParams.FLAG_NOT_FOCUSABLE;
params.x = 100;
params.y = 100;
params.height = WindowManager.LayoutParams.WRAP_CONTENT;
params.width = WindowManager.LayoutParams.WRAP_CONTENT;
params.gravity = Gravity.LEFT | Gravity.TOP;
wm.addView(view, params);
when you want to remove it
just
wm.removeView(v);
you also need permission
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
Good news, not so good news, bad news. Good new first.
It is possible to do what you want.
Now the not so good news.
You will have to write the launcher application from scratch(aka Home Screen). Yep, that involves doing all those nice and nifty things that the default launcher does(multiple pages, drag and drop, delete/add app icons, etc). Fortunately, its not as difficult as it sounds. Because the default launcher app itself is opensource. Though this code is complete, its not easy to read. A easier place to start would be the SDK
Android-SDK/samples/android-x/Home/
where x is the API level.
They have provided source code for an example home screen and it should give you a good start. With some perseverance and coffee, you should be able to modify the Launcher2 code to add a customized page of your own.
Now the Hard part.
Because a part of your goal is to keep the existing pages same and add a new page, getting this to work for all the flavors of android... HTC sense, Samsung TouchWiz, etc, etc is not a single person workload. They all have different features for the Home screen. Preserving these features and adding a new customized page is a tough task.