I'm working on an aplication that allows the user to select between multiple animations before setting the selection as currently running live wallpaper.
I've reviewed links with similar questions such as:
call Live wallpaper within application
And:
Setting live wallpaper programmatically
They address how to make the selections, but not the error I am seeing.
The first screen dispayed to the user is a selection screen that shows multiple wallpapers. Each wallpaper has a button for the user to click which indicates the selection of that wallpaper.
Each button has a unique ID. Each is found and assigned to an instance of a Button object, and each is registered with an OnClickListener.
Once a button is clicked, I use a switch statement to determine which button was pressed, I create a new Intent, indicate which wallpaper class I want to run, and I start the activity.
When I run this in the emulator, the application loads as expected. I see my selection screen and it correctly displays the various wallpaper selections. The problem happens when I select a wallpaper to run. Once I click on a button, the display turns white and remains stuck that way until I shut down the debugger.
Having run this in debug mode, I found that after clicking on a selection button, the code performs the switch statement, runs through the creation of the intent which calls the startActivity(intent) method and then breaks. Then the code jumps through the View.java, Handler.java, and Looper.java classes where it finally loops forever in the Looper.java class in a for loop that deals with a message queue.
This is the MainActivity where I set the initial layout view, set my buttons, and create the onClickListener:
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.selection);
// Capture our buttons from the selection layout
Button button_1 = (Button)findViewById(R.id.set1);
button_1.setOnClickListener(this);
// Capture our buttons from the selection layout
Button button_2 = (Button)findViewById(R.id.set2);
button_2.setOnClickListener(this);
// Capture our buttons from the selection layout
Button button_3 = (Button)findViewById(R.id.set3);
button_3.setOnClickListener(this);
}
// Implement the OnClickListener callback
public void onClick(View v) {
switch(v.getId())
{
//If button_1 was selected, set the first wallpaper.
case R.id.set1 :
setContentView(R.layout.activity_main);
Intent intent = new Intent(
WallpaperManager.ACTION_CHANGE_LIVE_WALLPAPER);
intent.putExtra(WallpaperManager.EXTRA_LIVE_WALLPAPER_COMPONENT,
new ComponentName(this, Wallpaper1.class));
startActivity(intent);
break;
//If button_2 was selected, set the second wallpaper.
case R.id.set2 :
setContentView(R.layout.activity_main);
intent = new Intent(
WallpaperManager.ACTION_CHANGE_LIVE_WALLPAPER);
intent.putExtra(WallpaperManager.EXTRA_LIVE_WALLPAPER_COMPONENT,
new ComponentName(this, Wallpaper2.class));
startActivity(intent);
break;
//If the Cuba button was selected, set the Cuba wallpaper.
case R.id.set3 :
setContentView(R.layout.activity_main);
intent = new Intent(
WallpaperManager.ACTION_CHANGE_LIVE_WALLPAPER);
intent.putExtra(WallpaperManager.EXTRA_LIVE_WALLPAPER_COMPONENT,
new ComponentName(this, Wallpaper3.class));
startActivity(intent);
break;
}
}
Here is the message loop where the execution gets stuck, iterating infinitely:
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
// This must be in a local variable, in case a UI event sets the logger
final Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
final long traceTag = me.mTraceTag;
if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
}
try {
msg.target.dispatchMessage(msg);
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
// Make sure that during the course of dispatching the
// identity of the thread wasn't corrupted.
final long newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
Log.wtf(TAG, "Thread identity changed from 0x"
+ Long.toHexString(ident) + " to 0x"
+ Long.toHexString(newIdent) + " while dispatching to "
+ msg.target.getClass().getName() + " "
+ msg.callback + " what=" + msg.what);
}
msg.recycleUnchecked();
}
The code doesn't seem to notice the click event until after correctly moving through the switch statement.
How can I get this to call the Intent correctly?
Related
I want to remove stacked Android Toasts after the user goes to another Fragment. I have Fragments that are stacked and in every Fragment, I have two buttons which triggers different Toast message. When operations of a Fragment is done and the user navigates to another Fragment or press back button Toasts are kept showing. This mainly happens when the user clicks buttons too fast and force Toasts to stack.
Or when I instantiate global Toast objects and call cancel() than both of toasts stop from showing in that lifecycle of a fragment no matter how many times the user tap button.
toast1 = new Toast(getContext());
toast2 = new Toast(getContext());
showFirstToast(toast1).show();
showSecondToast(toast2).show();
private Toast showFirstToast(Toast toast){
LayoutInflater inflater = getLayoutInflater();
View layout = inflater.inflate(R.layout.toast_layout_correct, (ViewGroup)
getActivity().findViewById(R.id.toast_layout));
toast.setDuration(Toast.LENGTH_SHORT);
toast.setView(layout);
return toast;
}
Do not use global Toast object instead you should use multiple instances of Toast. So, you can cancel it one by one.
toast1 = new Toast(getContext());
toast2 = new Toast(getContext());
showFirstToast(toast).show();
showSecondToast(toast).show();
toast1.cancel()
to avoid stacked toasts I reuse a single toast
Toast toast;
protected void showToast(final String text) {
if (toast == null)
toast = Toast.makeText(getActivity(), text, Toast.LENGTH_SHORT);
else
toast.setText(text); // smoother transition than cancel + new toast
toast.show();
}
#Override
public void onPause() {
if(toast != null)
toast.cancel();
super.onPause();
}
I found a custom BlurDialog on github for android. It opens up a new dialog window with options and blurs the background of the rest of the screen. I have it working perfectly, but I am running into an issue where if I select an item in the options list, it will launch the correct activity, but then when I hit the back button I get back to the previous activity and the dialog window is still open. The only way to close it is by clicking outside the dialog window.
I am trying to find out how to close the dialog window before launching the new activity, so that when the user goes back to that screen the dialog window isn't open anymore. I am still new to android, so I am sure I am missing something extremely simple, I just can't figure it out. Here is the "onCreateDialog" method in my fragment that creates the blurred dialog window...
#Override
#NonNull
public Dialog onCreateDialog(Bundle savedInstanceState) {
final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
View view = getActivity().getLayoutInflater().inflate(R.layout.fragment_profile_dialog, null);
TextView text = (TextView) view.findViewById(R.id.follow_or_unfollow);
if(isSelf) {
text.setText("Edit Profile");
} else {
text.setText((isFollowing) ? "UnFollow" : "Follow");
}
RelativeLayout followButton = (RelativeLayout) view.findViewById(R.id.follow_layout);
RelativeLayout chatButton = (RelativeLayout) view.findViewById(R.id.chat_layout);
followButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//NEED TO CLOSE DIALOG WINDOW HERE
if(isSelf) {
//activate ProfileEditActivity
getActivity().startActivity(new Intent(getActivity(), EditProfileActivity.class));
} else {
Map<String, Object> updates = new HashMap<>();
if(isFollowing) {
//unfollow
updates.put("/following/" + user.getUid() + "/users/" + userID, null);
updates.put("/followers/" + userID + "/users/" + user.getUid(), null);
} else {
updates.put("/following/" + user.getUid() + "/users/" + userID, true);
updates.put("/followers/" + userID + "/users/" + user.getUid(), true);
//follow
}
database.getReference().updateChildren(updates);
getFragmentManager().beginTransaction().remove(ProfileDialogFragment.this).commit();
}
}
});
chatButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Toast.makeText(getContext(), "Implement the start activity for chat", Toast.LENGTH_SHORT).show();
}
});
builder.setView(view);
return builder.create();
}
I have tried looking through the sample apps on the github page here Blurred Dialog Github
But it only shows how to activate the dialog, not how to actually close it when a user selects an item in the dialog. Everything else is working perfectly, if I click an item it launches the correct activity, and if I click outside the dialog the dialog closes. I just need to close it programmatically after a user clicks an item in the dialog. Thank you.
Instead of final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()) create dialog using final AlertDialog builder = new AlertDialog.Builder(getActivity()).create() and show the dilaog after stting view like dialog.show().
Whenver user clicks something on the screen you can close the dialog using the dialog object like dialog.dismiss() i.e inside your follow button click
followButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
dialog.dismiss()
//YOUR CODE SHOULD COME HERE
}
});
According to the developer site https://developer.android.com/reference/android/app/DialogFragment.html
"Note that in this case the fragment is not placed on the back stack, it is just added as an indefinitely running fragment. Because dialogs normally are modal, this will still operate as a back stack, since the dialog will capture user input until it is dismissed. When it is dismissed, DialogFragment will take care of removing itself from its fragment manager."
Maybe if you call dismiss() it will work.
Public methods
void dismiss()
Dismiss the fragment and its dialog.
The title says it all. How can I tell when onPause() is being called because of an orientation change instead of the back or home buttons being pressed?
I avoided the problem altogether by doing this instead:
You can use onWindowFocusChanged event instead of onPause. This function is not called when orientation changed.
#Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
Log.d(TAG, "FOCUS = " + hasFocus);
if (!hasFocus) finish();
}
But note: this event is called when activity is still visible (like onPause()), you should use onStop if you want to finish the activity when it is really and fully invisible:
private boolean isInFocus = false;
#Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
Log.d(TAG, "FOCUS = " + hasFocus);
isInFocus = hasFocus;
}
#Override
public void onStop() {
super.onStop();
if (!isInFocus) finish();
}
You cannot differentiate how onPause is called. What you could do is, You can override onKeyDown and look for back button and home button key events.
Have a flag that marks back/home button presses and check for this flag in onPause(). If this flag is not set, onPause is called cos of orientation change. However, there is a chance that your app is moved to background due to a phone call or alarm! So maynot be a perfect solution.
The other solution is to keep track of orientation changes in onConfigurationChanged
You probably want onSaveInstanceState instead of onPause
they serve similar function but onSaveInstanceState is not called when the user is backing out of the activity.
http://developer.android.com/reference/android/view/OrientationEventListener.html
This should work. Why don't you toast in this.
You can't. Simple as that. You can however measure the time it takes to reach onResume again and if the device was tilted by reading the display configuration.
An interval of 3 seconds is somewhat reasonable, also for slower devices.
Here are the relevant parts that we use:
protected void onCreate() {
...
orientation = getResources().getConfiguration().orientation;
}
protected void onResume() {
...
long time = SystemClock.elapsedRealtime() - pauseTime;
int o = getResources().getConfiguration().orientation;
Log.d(TAG, "pauseTime: " + pauseTime + " System: " + SystemClock.elapsedRealtime() + " elapsed pause time: " + time + " orientation now: " + o + " orientation then: " + orientation);
if (time < 3000 && o != orientation) {
// device was turned
}
orientation = o;
}
protected void onPause() {
...
pauseTime = SystemClock.elapsedRealtime();
}
protected void onSaveInstanceState(final Bundle outState) {
...
outState.putLong(PAUSE_TIME, pauseTime);
outState.putInt(ORIENTATION, orientation);
}
protected void onRestoreInstanceState(final Bundle savedInstanceState) {
...
pauseTime = savedInstanceState.getLong(PAUSE_TIME, -1);
orientation = savedInstanceState.getInt(ORIENTATION, -1);
}
The above code is running on about 40k devices and reliably works.
I have this code that allows me to press a button to turn on my phones flashlight. What would be the best way to keep the light on, while the application is closed? I heard asynctask is good, but I read that it's meant for a background task that will communicate with the UI. What kind of "thread" should I use for this type of "application".
My onClickListener code:
button.setOnClickListener(new OnClickListener() {
public void onClick(View arg0) {
//If Flag is set to true
if (isFlashOn) {
Log.i("info", "torch is turned off!");
//Set the flashmode to off
p.setFlashMode(Parameters.FLASH_MODE_OFF);
//Pass the parameter ti camera object
camera.setParameters(p);
//Set flag to false
isFlashOn = false;
//Set the button text to Torcn-ON
button.setText("Torch-ON");
}
//If Flag is set to false
else {
Log.i("info", "torch is turned on!");
//Set the flashmode to on
p.setFlashMode(Parameters.FLASH_MODE_TORCH);
//Pass the parameter ti camera object
camera.setParameters(p);
//Set flag to true
isFlashOn = true;
//Set the button text to Torcn-OFF
button.setText("Torch-OFF");
}
}});
}
Sounds that you need a service
A Service is an application component representing either an application's desire to perform a longer-running operation while not interacting with the user or to supply functionality for other applications to use
What I want to create is a popup style application.
I have a service in the background - something arrives on the queue and i want an activity to start to inform the user - very very similar to the functionality of SMSPopup app.
So I have the code where something arrives on the queue and it calls my activity.
However for some reason the activity always shows on top of the originally started activity instead of just appearing on the main desktop of the android device.
As an example:
I have the main activity which is shown when the application is run
I have the service which checks queue
I have a popup activity.
When i start the main activity it starts the service - I can now close this.
I then have something on the queue and it creates the popup activity which launches the main activity with the popup on top of it :S How do I stop this and have it behave as i want...
The popup class is :
public class SMSPopup extends Activity implements OnClickListener{
public static String msg;
#Override
public void onCreate(Bundle bundle){
super.onCreate(bundle);
// Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_LONG).show();
this.setContentView(R.layout.popup);
TextView tv = (TextView)findViewById(R.id.txtLbl);
Intent intent = getIntent();
if (intent != null){
Bundle bb = intent.getExtras();
if (bb != null){
msg = bb.getString("com.andy.tabletsms.message");
}
}
if(msg == null){
msg = "LOLOLOL";
}
tv.setText(msg);
Button b = (Button)findViewById(R.id.closeBtn);
b.setOnClickListener(this);
}
#Override
public void onClick(View v) {
this.finish();
}
}
and I call the activity from a broadcast receiver which checks the queue every 30 seconds or so :
if(main.msgs.size()>0){
Intent testActivityIntent = new Intent(context.getApplicationContext(), com.andy.tabletsms.work.SMSPopup.class);
testActivityIntent.putExtra("com.andy.tabletsms.message", main.msgs.get(0));
testActivityIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(testActivityIntent);
}
The layout is here : http://pastebin.com/F25u6wdM
This is against the design practice suggested by Android. See http://developer.android.com/guide/topics/ui/notifiers/notifications.html
A background Service should never launch an Activity on its own in order to receive user interaction.
You could show the message in a Toast and/or notification. From the notification, you could start a new intent.