Background
Starting from Android O, it's possible to create pinned shortcuts, which (on supported launchers) show a dialog to confirm the creation of them:
ShortcutInfoCompat pinShortcutInfo = new ShortcutInfoCompat.Builder(context, uniqueShortcutId)
.setShortLabel(label)
.setIntent(shortcutIntent)
.setLongLabel(label)
.setIcon(IconCompat.createWithBitmap(bitmap))
.build();
ShortcutManagerCompat.requestPinShortcut(this, pinShortcutInfo , null);
Docs:
https://developer.android.com/reference/android/content/pm/ShortcutManager.html
https://developer.android.com/guide/topics/ui/shortcuts.html
The problem
Sometimes, the pinned shortcut is not relevant anymore. For example, it points to something that doesn't exist anymore.
In this case, I want to be able to remove it.
What I've tried
I thought this is possible by the next code, but it doesn't, because it is probably about dynamic shortcuts, which is something else :
ShortcutManager shortcutManager = (ShortcutManager) getSystemService(SHORTCUT_SERVICE);
final List<ShortcutInfo> pinnedShortcuts = shortcutManager.getPinnedShortcuts();
final ArrayList<String> shortcutIdsToRemove = new ArrayList<>();
for (ShortcutInfo pinnedShortcut : pinnedShortcuts) {
final Intent pinnedShortcutIntent = pinnedShortcut.getIntent();
shortcutIdsToRemove.add(pinnedShortcut.getId());
}
shortcutManager.removeDynamicShortcuts(shortcutIdsToRemove);
// this also doesn't work : shortcutManager.disableShortcuts(shortcutIdsToRemove);
The question
How can I remove pinned shortcuts? Is it even possible?
Update: seems it isn't possible, as Google mentioned here.
So far, this API seems very restricting to me, as it has so many disadvantages:
The created icon image cannot be created from a resource ID.
On the launcher, the created icon has a tiny icon of the app that created it.
The icon cannot be removed via the API (only disabled), so if you created one that points to another app, and this app was removed, you won't be able to remove it.
The creation cannot be in the background, as it requires a confirmation dialog. It also cannot be created in a batch. Only one after another.
All pinned shortcuts your app has created will be removed if your app was removed.
So, my question now is:
Is there any way to create and remove a shortcut using the previous API, using an adb command, with root if needed ?
Is it possible to remove specific pinned shortcuts using adb command , with root if needed?
disableShortcuts() is the best you can do. It will show the user a custom error message when they try to select the disabled shortcut.
From the official documentation:
Shortcut limitations
Although you can publish up to five shortcuts (static and dynamic shortcuts combined) at a time for your app, most launchers can only display four.
However, there is no limit to the number of pinned shortcuts to your app that users can create. Even though your app cannot remove pinned shortcuts, it can still disable them.
Another section:
Because your app and its users can pin shortcuts to the device's launcher, it's possible that these pinned shortcuts could direct users to actions within your app that are out of date or no longer exist. To manage this situation, you can disable the shortcuts that you don't want users to select by calling disableShortcuts(), which removes the specified shortcuts from the static and dynamic shortcuts list and disables any pinned copies of these shortcuts. You can also use an overloaded version of this method, which accepts a CharSequence as a custom error message. That error message then appears when users attempt to launch any disabled shortcut.
Note: If you remove some of your app's static shortcuts when you update your app, the system disables these shortcuts automatically.
Related
<shortcuts xmlns:android="http://schemas.android.com/apk/res/android">
<shortcut
android:shortcutId="compose"
android:enabled="true"
android:icon="#drawable/compose_icon"
android:shortcutShortLabel="#string/compose_shortcut_short_label1"
android:shortcutLongLabel="#string/compose_shortcut_long_label1"
android:shortcutDisabledMessage="#string/compose_disabled_message1">
<intent
android:action="android.intent.action.VIEW"
android:targetPackage="com.example.myapplication"
android:targetClass="com.example.myapplication.ComposeActivity" />
<!-- This -->
<categories android:name="android.shortcut.conversation" />
</shortcut>
</shortcuts>
What other value is available? Do I need to include this category and what if I delete it?
I did not find this in the official documentation - https://developer.android.com/guide/topics/ui/shortcuts.html
categories tag is used to provide a grouping for the types of actions that your app's shortcuts perform. One of the available groups is android.shortcut.conversation, and this is used if you want to add a shortcut to conversation of chat application. For example, a shortcut to the most recent chat head. You would only need to add this in your shortcuts.xml, when you want to provide the said shortcut. Otherwise you don't need it. You can delete it.
For API level 26 or lower this is the only value that is avaliable. But for higher versions there are multiple.
For a list of supported shortcut categories you can see this page.
At this moment only one type supported category is android.shortcut.conversation. You can find it in ShortcutInfo
/**
* Shortcut category for messaging related actions, such as chat.
*/
public static final String SHORTCUT_CATEGORY_CONVERSATION = "android.shortcut.conversation";
Also in
/**
* Sets categories for a shortcut. Launcher apps may use this information to
* categorize shortcuts.
*
* #see #SHORTCUT_CATEGORY_CONVERSATION
* #see ShortcutInfo#getCategories()
*/
#NonNull
public Builder setCategories(Set<String> categories) {
mCategories = categories;
return this;
}
Shortcut category for messaging related actions, such as chat.
TL;DR in 2022: Seems like the "category" inner element became a forgotten feature of Android Shortcuts, and there only ended up being that one pre-defined "Conversation" category. Capabilities, on the other hand, are very well fleshed out and fill those boots quite well! Check out the link below for what capabilities can help you unlock!
In more detail as of 2022, Android API Level 25 introduced the ability to define shortcuts, letting you provide the user with a static set of shortcuts into your app for common actions like creating a new email as well as a dynamic set of shortcuts like sending a message to a recent contact.
It seems that the "category" inner element was intended to group certain similar shortcuts together. Unfortunately it seems the idea was abandoned likely due to the limited number of shortcuts that could appear in the small popup menu. These days the most I've seen is 5, and it can definitely vary based on your device. As a result of the limited space, it seems the only category that has been defined, even today with API level 32 available, is the "Conversation" category.
Due to its limited development, I find it best 99% of the time to leave off the "category" inner element in favor of the "capability" inner element which has quite the long list of pre-defined options that correspond to Built-In Intents (which can add amazing Google Assistant actions to your app)!
Here's the list of all of them!
Starting with Android 8.0 (Oreo) / API level 26, Android shows contextual actions for highlighted text (e.g. "Call" action if a phone number is selected). Also, Android automatically selects multiple words that belong together (e.g. a whole street address). This is called "Smart Text Selection".
This is how you register a new TextClassifier:
TextClassificationManager manager =
(TextClassificationManager) getSystemService(Context.TEXT_CLASSIFICATION_SERVICE);
TextClassifier c = manager.getTextClassifier();
manager.setTextClassifier(new MyTextClassifier());
MyTextClassifier implements the TextClassifier interface and implements suggestSelection() and classifyText().
classifyText() returns a TextClassification object which has a title and an Intent which describes the contextual action to perform.
Here is my question (finally): If I register my TextClassifier with the TextClassificationManager it works for my own app only.
Is there any way for defining a TextClassifier which can be used by other apps?
I would like to create an app which globally registers a new custom TextClassifier.
That way I could write an app that adds system-wide support for, let's say, song names (assuming I have a list of all song names I want to support). EditTexts would automatically select "Smells Like Teen Spirit" even though the user just long-clicked "Teen". And a contextual action "Search on Google Play Music" could pop up next to "Cut", "Copy" etc.
Unfortunately, in Android O, you won't be able to make other apps use your custom TextClassifier.
But if you'd like to encourage other apps to take advantage of your custom TextClassifier, you can create a library with your custom TextClassifier that can be built into other apps and set as the TextClassifier.
I'm programming an app using android studio. I want to know in which way I can do a tutorial that users will see only the first time that use the app. Tutorial like image or screenshoots
Can someone help me? Thanks
I encountered this thread while looking for a solution for running a tutorial only at the first time (as rbaleksandar suggested), so in case it will be helpful for someone someday, here's a template of a solution that works for me (using the SharedPreferences API):
#Override
protected void onResume() {
super.onResume();
String tutorialKey = "SOME_KEY";
Boolean firstTime = getPreferences(MODE_PRIVATE).getBoolean(tutorialKey, true);
if (firstTime) {
runTutorial(); // here you do what you want to do - an activity tutorial in my case
getPreferences(MODE_PRIVATE).edit().putBoolean(tutorialKey, false).apply();
}
}
EDIT - BONUS - If you're into app tutorial - I'm messing now with the ShowcaseView library (which is amazing - try it out). Apparently they have some shortcut for that issue using a method called singleShot(long) - its input is a key for the SharedPreferences, and it does the exact same thing - runs only in the first activation. Example of usage (taken from here):
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_single_shot);
Target viewTarget = new ViewTarget(R.id.button, this);
new ShowcaseView.Builder(this)
.setTarget(viewTarget)
.setContentTitle(R.string.title_single_shot)
.setContentText(R.string.R_string_desc_single_shot)
.singleShot(42)
.build();
}
You could always code your own solution, but, let us not reinvent the wheel.
Check this Android Library:
Tour Guide Repository
It allows you to add pointers in your screen, so the user knows where is he supposed to touch next.
It's pretty easy to use, you only need to point to the element you want the user to touch.
From the doc:
Let's say you have a button like this where you want user to click on:
Button button = (Button)findViewById(R.id.button);
You can add the tutorial pointer on top of it by:
TourGuide mTourGuideHandler = TourGuide.init(this).with(TourGuide.Technique.Click)
.setPointer(new Pointer())
.setToolTip(new ToolTip().setTitle("Welcome!").setDescription("Click on Get Started to begin..."))
.setOverlay(new Overlay())
.playOn(button);
Hope this helps!
Some links to libraries for creating introduction and/or tutorial screens.
Horizontal cards like Google Now:
https://github.com/PaoloRotolo/AppIntro
Tutorial screen:
https://github.com/amlcurran/ShowcaseView
As far as I understand the question is not How do I create a tutorial? (as the people who have already posted an answer have concluded) but instead How to show a tutorial upon first launch only?. So here are my two cents on this topic:
I'm not familiar with how your Android app stores its configuration data but I will assume that it's either in a database (SQLite) or a text file (plaintext, YAML, XML - whatever). Add a configuration entry to wherever the app's settings are being stored - something like tutorial_on : false, tutorial_on : 1 etc. depending on the format the configuration is represented in.
The way configurations work is that whenever an app (or software in general) is launched it has to be loaded in the app itself. So add the following to your app (where and how is up to you and your app design):
Check tutorial_on entry
If tutorial_on is set to true/1 whatever
2.1 Display tutorial
2.2 Change tutorial_on to false/0 whatever
2.3 Store the result in your configuration
Continue using the app
By doing so the first time your app launches the flag responsible for displaying the tutorial will be toggled and afterwards every time you start the app the toggle flag will be read leading to omitting the tutorial.
Personally I would suggest that you an option similar to Don't show tutorial anymore along with a description how to re-enable it (by triggering some action in that app's menu etc.). This has two major benefits:
Improved user experience - users like to have control (especially over trivial matters such as showing or hiding a tutorial). Whenever you take the control away from them, they get pissed off.
Enable your user to re-learn forgotten things - a general rule of thumb is to create apps that should not burden the user with a lot of stuff to remember. That is why things should be self-explanatory. However sometimes you may want to do that nonetheless. By adding the possibility that the user re-launches (by simply resetting the tutorial_on flag and repeating the steps from above) the tutorial allows just that - refreshing a user's memory.
I have a few notifications running on my app built with NotificationCompat
Depending on the type, they show background bitmaps, or list of text, also most of them have 1 or 2 actions using the code:
builder.addAction(R.drawable.ic_notification, text, pendingIntent)
some of those actions makes sense for a watch (for example: "like" or "reply") and some doesn't (for example: "view album").
I thought I could use the setLocalOnly(boolean) method for it, but I found out that it is applied to the whole notification, not just to individual actions.
I've also been checking on NotificationCompat.Action and NotificationCompat.Action.WearableExtender but couldn't find anything that would be relevant.
So the question:
is there a way to make the notification show on the watch, but only with some of the actions but not others?
Please see docs in the paragraph "Specify wearable-only actions".
Sometimes when I'm working with my android projects, and hook up my phone, the logcat in Eclipse starts to report EVERYTHING that's happening on my phone, not just the stuff relative to the project I'm working on. It only does this sometimes though.
How do I stop it from showing everything and just show the things relative to my project?
EDIT:
I forgot to say i already know about filters, sorry. I was just wondering why sometimes eclipses logcat shows everything my phone is doing, while other times it only shows what's relative to the project i'm currently working with when running it on the phone.
I forgot to say i already know about filters, sorry.
Then it is because you have a filter selected and/or eclipse has encountered an error and is just not showing everything it should be.
First Answer
Next to your logcat window should be a Filter window. Create a filter there. Then select the filter by clicking the filter you have made or was put there automatically by eclipse.
You can filter on several things.
Most people will create a static string in their Main Activity/Service containing the application name. Use this static string as your TAG for all of your Logs. Then you can filter on this string you put for the static string.
Also, right clicking in the logcat window will bring up a filter dialog.
You can click on the session filter (left)
Use
Log.d("key","value");
Log.d("key1","value");
Log.d("key2","value");
Log.d("key2","value");
If you want to see only key1 messages ,then go to Logcat
click on add new logcat filter at top left corner(green color + symbol)
then a dialog box will be shown
then a dialog box will be shown, in that write Filter Name ie anyname
and in , by Log Tag write key1 and click on ok button.Now you will see a new filter on left side of your logcat
click on that,you will get only key1 messages
I could fix this by selecting my app in the DDMS-view.
It is important to select the app and not only the device. Latter will only create this useless "(Session-Filter)"
And this happens "sometimes" quite like the author asked for, i think if you change your mobile phone or just disconnect it.
http://developer.android.com/tools/debugging/ddms.html#logcat
You can also setup your own custom filter to specify more details such as filtering messages with the log tags or with the process id that generated the log message. The add filter, edit filter, and delete filter buttons let you manage your custom filters.
Use filters to define what you want to look at.
If you are using Eclipse, when viewing the LogCat view, there is a little green "+" button in the upper right corner. This will allow you to create a filter. Simply give your filter a name and input the TAG it should filter by.
If you are developing with Eclipse creating a log filter is what you are looking for.
If you are using logcat through adb from the command line: Filter LogCat to get only the messages from My Application in Android?