Save in view when rotate screen - android

my layout is very heavy, so when you turn the screen takes a long time. How can I save my view "onSaveInstanceState" ??
My code:
if (tab.getPosition() == 0) {
/*
* ----------------- TAB DATA -----------------
*/
try {
System.gc();
// initialize the class that needs to load the Activity
myLayout = new TableMainLayout(this);
// I tried to give some time to load, but that's not good!
synchronized (this) {
wait(5000);
}
setContentView(myLayout);
} catch (Exception e) {
Log.i("link", "Errore actionBarTabs update Series: " + e);
}
}
Thanks

I understood when you change the orientation app does not want to read the data back, well put this code in manifest file in your activity that you do not want to read again.
android:configChanges="orientation"
This code allows you to freeze your activity.
For example:
<activity
android:name=".MainActivity"
android:configChanges="orientation"
android:label="#string/app_name"
android:theme="#style/AppBaseTheme" >
</activity>

Related

How to detect or monitor touching edittext in another android app?

Is it possible to monitor touching edit text behavior in another android app? For example, when touching edit text in specific android app, paste some words automatically which have been set up before.
PS. if it is not possible, any way to receive soft keyboard pop up broadcast ?
It's possible to detect when an EditText is touched, even when the EditText belongs to another app. However, this can only be done through Accessibility Services.
First, you need to create a serviceconfig.xml file in your xml folder:
<?xml version="1.0" encoding="utf-8"?>
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
android:description="#string/accessibility_permission_desc"
android:accessibilityEventTypes="typeAllMask"
android:accessibilityFeedbackType="feedbackGeneric"
android:notificationTimeout="100"
android:canRetrieveWindowContent="true"
/>
Second, you need to create an AccessibilityService, like so:
public class MyAccessibilityService extends AccessibilityService {
...
#Override
public void onAccessibilityEvent(AccessibilityEvent accessibilityEvent) {
switch(accessibilityEvent.getEventType()) {
case AccessibilityEvent.TYPE_VIEW_CLICKED:
case AccessibilityEvent.TYPE_VIEW_FOCUSED:
try {
Class className = Class.forName(accessibilityEvent.getClassName().toString());
if (EditText.class.isAssignableFrom(className)) {
// An EditText was Clicked or Focused
// Use other methods from the accessibilityEvent to do what
// you need to do
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
break;
}
}
...
}
Third, you need to add the service to the AndroidManifest.xml:
<service android:name=".MyAccessibilityService"
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/serviceconfig" />
</service>
Finally, you need to enable the AccessibilityService through the Accessibility Settings. You can go directly to there through:
startActivity(new Intent(android.provider.Settings.ACTION_ACCESSIBILITY_SETTINGS));
Edit:
You can't get the EditText through an AccessibilityEvent. Instead, you need to get an AccessibilityNodeInfo and perform typical EditText features through this AccessibilityNodeInfo.
To get the AccessibilityNodeInfo, you'll need to call this code:
AccessibilityNodeInfo nodeInfo = accessibilityEvent.getSource()==null ? null : accessibilityEvent.getSource();
Then, you can perform specific actions like setText() like so:
if (nodeInfo != null) {
nodeInfo.refresh();
Bundle bundle = new Bundle();
bundle.putString(AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, newString);
nodeInfo.performAction(AccessibilityNodeInfo.ACTION_SET_TEXT, bundle);
}
Notice how I'm using performAction() onto the AccessibilityNodeInfo and using the action AccessibilityNodeInfo.ACTION_SET_TEXT and passing in a bundle with the key AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE.
This is almost the same as calling setText() on the EditText View.
If you don't want to setText() and want to just directly paste text into the EditText, you can use:
if (nodeInfo != null) {
nodeInfo.refresh();
nodeInfo.performAction(AccessibilityNodeInfo.ACTION_PASTE);
}

how to keep my app language without changing when changing screen orientation?

I finished my app with multi languages , but when the device orientation is changed to landscape then app's language is changed .
can I use (onSaveInstanceState) method to keep app language without changing when rotating screen?
what is the code I have to insert ??
Try this in your manifest
<activity
android:name=".MainActivity"
android:configChanges="keyboardHidden|orientation|screenSize">
</activity>
And then
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// you can do something here
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
// orientation_landscape
Toast.makeText(this, "orientation_landscape", Toast.LENGTH_SHORT).show();
} else {
// orientation_portrait
Toast.makeText(this, "orientation_portrait", Toast.LENGTH_SHORT).show();
}
}

How to use Accessibility Services for "Taking Action for Users"?

Background
Back a few years ago, I asked how TeamViewer allows the user to control the device without normal interaction with the device. I was told it's a special "backdoor" that manufacturers allow specifically for this app, and only possible using root priviledge for other apps.
Seeing that an app like "Airplane Mode Shortcut" allows to toggle airplane mode, by automatic navigation to its screen and toggling the switch, it made me realize this situation has changed.
The problem
It is said in the docs:
Starting with Android 4.0 (API Level 14), accessibility services can
act on behalf of users, including changing the input focus and
selecting (activating) user interface elements. In Android 4.1 (API
Level 16) the range of actions has been expanded to include scrolling
lists and interacting with text fields. Accessibility services can
also take global actions, such as navigating to the Home screen,
pressing the Back button, opening the notifications screen and recent
applications list. Android 4.1 also includes a new type of focus,
Accessibilty Focus, which makes all visible elements selectable by an
accessibility service.
These new capabilities make it possible for developers of
accessibility services to create alternative navigation modes such as
gesture navigation, and give users with disabilities improved control
of their Android devices.
But there is no more information about how to use it.
Only samples I've found are at the bottom, but those are very old and a part of the apiDemos bundle.
The question
How do I make a service that can query, focus, click, enter text, and perform other UI related operations?
By implementing AccessibilityService (https://developer.android.com/training/accessibility/service.html) you get access to that features.
You can either inspect or perform action on the element lastly interacted by user or inspect whole application which currently active.
Intercept user events by implementing onAccessibilityEvent(AccessibilityEvent event), here you can retrieve virtual view (representing original view) with event.getSource() and then inspect it with getClassName() or getText() or anything you find in the documentation.
Inspect whole application by calling getRootInActiveWindow() and iterate throught tree of virtaul views with getRootInActiveWindow().getChild(index).
Both getRootInActiveWindow() and event.getSource() return AccessibilityNodeInfo, on which you can invoke performAction(action) and do something like Click, Set Text, etc..
Example: Play Store
Search for 'facebook' app and open it's page on play store, once you opened the play store app.
#Override
public void onAccessibilityEvent(final AccessibilityEvent event) {
AccessibilityNodeInfo rootInActiveWindow = getRootInActiveWindow();
//Inspect app elements if ready
if (rootInActiveWindow != null) {
//Search bar is covered with textview which need to be clicked
List<AccessibilityNodeInfo> searchBarIdle = rootInActiveWindow.findAccessibilityNodeInfosByViewId("com.android.vending:id/search_box_idle_text");
if (searchBarIdle.size() > 0) {
AccessibilityNodeInfo searchBar = searchBarIdle.get(0);
searchBar.performAction(AccessibilityNodeInfo.ACTION_CLICK);
}
//Check is search bar is visible
List<AccessibilityNodeInfo> searchBars = rootInActiveWindow.findAccessibilityNodeInfosByViewId("com.android.vending:id/search_box_text_input");
if (searchBars.size() > 0) {
AccessibilityNodeInfo searchBar = searchBars.get(0);
//Check is searchbar have the required text, if not set the text
if (searchBar.getText() == null || !searchBar.getText().toString().equalsIgnoreCase("facebook")) {
Bundle args = new Bundle();
args.putString(AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, "facebook");
searchBar.performAction(AccessibilityNodeInfo.ACTION_SET_TEXT, args);
} else {
//There is no way to press Enter to perform search, so find corresponding suggestion and click
List<AccessibilityNodeInfo> searchSuggestions = rootInActiveWindow.findAccessibilityNodeInfosByViewId("com.android.vending:id/suggest_text");
for (AccessibilityNodeInfo suggestion : searchSuggestions) {
if(suggestion.getText().toString().equals("Facebook")) {
//We found textview, but its not clickable, so we should perform the click on the parent
AccessibilityNodeInfo clickableParent = suggestion.getParent();
clickableParent.performAction(AccessibilityNodeInfo.ACTION_CLICK);
}
}
}
}
}
}
EDIT: full code below:
MyAccessibilityService
public class MyAccessibilityService extends AccessibilityService {
#Override
public void onCreate() {
super.onCreate();
Log.d("MyAccessibilityService", "onCreate");
}
#Override
public void onAccessibilityEvent(final AccessibilityEvent event) {
Log.d("MyAccessibilityService", "onAccessibilityEvent");
AccessibilityNodeInfo rootInActiveWindow = getRootInActiveWindow();
//Inspect app elements if ready
if (rootInActiveWindow != null) {
//Search bar is covered with textview which need to be clicked
List<AccessibilityNodeInfo> searchBarIdle = rootInActiveWindow.findAccessibilityNodeInfosByViewId("com.android.vending:id/search_box_idle_text");
if (searchBarIdle.size() > 0) {
AccessibilityNodeInfo searchBar = searchBarIdle.get(0);
searchBar.performAction(AccessibilityNodeInfo.ACTION_CLICK);
}
//Check is search bar is visible
List<AccessibilityNodeInfo> searchBars = rootInActiveWindow.findAccessibilityNodeInfosByViewId("com.android.vending:id/search_box_text_input");
if (searchBars.size() > 0) {
AccessibilityNodeInfo searchBar = searchBars.get(0);
//Check is searchbar have the required text, if not set the text
if (searchBar.getText() == null || !searchBar.getText().toString().equalsIgnoreCase("facebook")) {
Bundle args = new Bundle();
args.putString(AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, "facebook");
searchBar.performAction(AccessibilityNodeInfo.ACTION_SET_TEXT, args);
} else {
//There is no way to press Enter to perform search, so find corresponding suggestion and click
List<AccessibilityNodeInfo> searchSuggestions = rootInActiveWindow.findAccessibilityNodeInfosByViewId("com.android.vending:id/suggest_text");
for (AccessibilityNodeInfo suggestion : searchSuggestions) {
if (suggestion.getText().toString().equals("Facebook")) {
//We found textview, but its not clickable, so we should perform the click on the parent
AccessibilityNodeInfo clickableParent = suggestion.getParent();
clickableParent.performAction(AccessibilityNodeInfo.ACTION_CLICK);
}
}
}
}
}
}
#Override
public void onInterrupt() {
}
}
AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.findfacebookapp">
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<service
android:name=".MyAccessibilityService"
android:label="#string/accessibility_service_label"
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/accessibility_service_config"/>
</service>
</application>
</manifest>
res/xml/accessibility_service_config.xml
<?xml version="1.0" encoding="utf-8"?>
<accessibility-service
xmlns:android="http://schemas.android.com/apk/res/android"
android:accessibilityEventTypes="typeAllMask"
android:accessibilityFeedbackType="feedbackAllMask"
android:accessibilityFlags="flagDefault"
android:canRequestEnhancedWebAccessibility="true"
android:canRetrieveWindowContent="true"
android:description="#string/app_name"
android:notificationTimeout="100"/>
MainActivity
public class MainActivity extends AppCompatActivity {
public void onEnableAccClick(View view) {
startActivityForResult(new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS), 1);
}
}

How to get the result of a loader if the screen was rotated during its job?

I heard loaders can help save the result of an asynchronous job during orientation changes. I have a fragment that executes a loader with some arguments. What should I do to reconnect to the loader? Important note: I don't want to restart the loader if its result was already processed by the LoaderCallbacks.onLoadFinished().
More detailed: I have a fragment with a text field. When the user inputs some text and presses Enter I should start search with a network request. I do it by starting a loader
private void loadFirstPage() {
LoaderManager loaderManager = getLoaderManager();
data.currentPage = 1;
Bundle args = new Bundle();
args.putString(VacanciesAsyncLoader.ARG_SEARCH_TEXT, data.query);
args.putInt(VacanciesAsyncLoader.ARG_ITEMS_PER_PAGE, Const.ITEM_PER_PAGE);
args.putInt(VacanciesAsyncLoader.ARG_PAGE_NUMBER, data.currentPage);
loaderManager.restartLoader(GET_VACANCIES_LOADER_ID, args, this);
}
#Override
public void onViewCreated(Bundle savedInstanceState) {
super.onViewCreated(savedInstanceState);
if (savedInstanceState == null) {
// ...
} else {
data = savedInstanceState.getParcelable(KEY_DATA);
restoreViewState(data);
reconnectLoaderIfNeeded();
}
}
private void reconnectLoaderIfNeeded() {
EnumSet<State> loadingStates =
EnumSet.of(State.REFRESHING, State.LOADING_FIRST_PAGE, State.LOADING_ADDITIONAL_PAGE);
if (loadingStates.contains(data.state)) {
getLoaderManager().initLoader(GET_VACANCIES_LOADER_ID, null, this);
}
}
And I want to reconnect to it when the screen rotates. And if I processed its result, I don't want to trigger it again.
If this is just a one-off request, the typical pattern for this should be:
Initiate the request:
getLoaderManager().restartLoader(LOADER_ID, args, callbacks);
In onCreate(), check to see if the Loader is still running:
if (savedInstanceState != null) {
// If it exists, init with null arguments (since they won't
// be used) to reconnect the callbacks
if (getLoaderManager().getLoader(LOADER_ID) != null) {
getLoaderManager().initLoader(LOADER_ID, null, callbacks);
}
}
In your onLoadFinished(), destroy the loader:
getLoaderManager().destroyLoader(LOADER_ID);
Assuming you've implemented your Loader properly, this should do the trick.
You set this code in your Activity (for fragment).
AndroidManifest.xml :
android:configChanges="orientation|keyboardHidden"
...
<activity
android:name=".MainActivity"
android:label="#string/app_name"
android:configChanges="orientation|keyboardHidden"
>
This article helped me a lot in dealing with orientation changes regarding asynchronous tasks. It has to do with retaining Fragments:
http://www.androiddesignpatterns.com/2013/04/retaining-objects-across-config-changes.html
Hope this helps you as it did me

Google Places API for android - getting 0 photos for cities

I am using Google places API for android to let the user select cities in the world. Then I use the placeId to get an image to something similar to google maps.
Picture example
Every single time I'm getting the photos bundle successfully but it contains no images. It works just fine if I use the placeId of any restaurant or cafe or any other single spot but not for a whole city.
Here's the method I'm using to get the images.
public void loadPlaceImage(final ImageView imageView, String placeId) {
/**
* Load a bitmap from the photos API asynchronously
* by using buffers and result callbacks.
*/
Places.GeoDataApi.getPlacePhotos(mGoogleApiClient, placeId)
.setResultCallback(new ResultCallback<PlacePhotoMetadataResult>() {
#Override
public void onResult(PlacePhotoMetadataResult photos) {
if (!photos.getStatus().isSuccess()) {
Log.d(TAG, "Couldn\'t receive photos bundle successfully.");
return;
}
Log.d(TAG, "Photo bundle received successfully");
PlacePhotoMetadataBuffer photoMetadataBuffer = photos.getPhotoMetadata();
if (photoMetadataBuffer.getCount() > 0) {
// Display the first bitmap in an ImageView in the size of the view
photoMetadataBuffer.get(0)
.getScaledPhoto(mGoogleApiClient, imageView.getWidth(),
imageView.getHeight())
.setResultCallback(new ResultCallback<PlacePhotoResult>() {
#Override
public void onResult(PlacePhotoResult placePhotoResult) {
if (!placePhotoResult.getStatus().isSuccess()) {
Log.d(TAG, "Couldn\'t retrieve the photo successfully.");
return;
}
Log.d(TAG, "Successfully retrieved photo from photo bundle.");
imageView.setImageBitmap(placePhotoResult.getBitmap());
}
});
} else {
Log.d(TAG, "0 images in the buffer.");
}
photoMetadataBuffer.release();
}
});
}
I used your code in my android studio, it hadn't problem in your code.
I guess you forgot to add meta-data in Manifest.
<application
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="YOURKEY"/>
</application>
it is for reference to set up your "Android KEY"
https://developers.google.com/places/android-api/signup
https://console.developers.google.com/apis (this Link can set your key)
By the way, you can use:
Log.d(TAG,"result getStatus "+result.getStatus().getStatus());
to check your error message, hope it will help you

Categories

Resources