My app listens for an Intent fired by a third party app when an Activity in that app is shown. The Intent is received in a BroadcastReceiver in my app. I want to start an Activity from the BroadcastReceiver which will show as a Dialog over the existing activity (that fired the Intent).
#Override
public void onReceive(final Context context, Intent intent) {
String action = intent.getAction();
Log.d(TAG, ">>>>>>>>> Action:" + action);
if ("clover.intent.action.V1_ORDER_BUILD_START".equals(action)) {
Intent i = new Intent(context.getApplicationContext(), ActiveOrderActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);
}
}
The Intent clover.intent.action.V1_ORDER_BUILD_START is fired by a different app which my app listens for. When this Intent is fired, an Activity is already open (see the background activity in the picture below).
Now I want to show an Activity in my app as Dialog over the already shown activity, just like the "Add Customer to Order" in the image below.
As shown in the code above, I am starting an Activity from BroadcastReceiver, but when it starts, it comes to foreground and the previous Activity is not shown.
See below for an example of what I want to achieve,
Maybe you should create
public class MyDialog extends DialogFragment {
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
// Get the layout inflater
LayoutInflater inflaterViewObject = LayoutInflater.from(getActivity());
// Inflate and set the layout for the dialog
// Pass null as the parent view because its going in the dialog layout
final View DialogView = inflaterViewObject.inflate(R.layout.dialog, null);
final AlertDialog Dialog = new AlertDialog.Builder(getActivity()).create();
Dialog.setView(DialogView);
DialogView.findViewById(R.id.dialog_YES).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//your YES logic
Dialog.dismiss();
}
});
DialogView.findViewById(R.id.dialog_NO).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//Your NO LOGIC
Dialog.dismiss();
}
});
// return dialog object (later on .show());
return Dialog;
}
Later you write in your choosen place (in BrodcastReciever)
MyDialog dialogObject = new MyDialog();
dialogObject.show(getFragmentManager(), "tag name for the dialog fragment.");
Related
I am working on an App that has a DialogBuilder Class where I implemented all the Dialogs for the App in order to be able to call them in other Services or Activities; that works very well except in one Activity, where I tried everything to pass the context - it is not working; hence, I would be more than delighted for any hints or help on this, thanks!
The Dialog:
public static void bookingConfirmationDialog(Context mContext) {
if(mContext != null) {
final Dialog dialog = new Dialog(GoldbekStorageApp.getInstance(), 0);
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setCancelable(true);
dialog.setContentView(R.layout.new_booking_layout);
dialog.getWindow().setBackgroundDrawable(new ColorDrawable(android.graphics.Color.TRANSPARENT));
TextView textView = dialog.findViewById(R.id.messageId);
textView.setText(GoldbekStorageApp.getInstance().messageId);
Button okButton = dialog.findViewById(R.id.ok);
okButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
dialog.dismiss();
}
});
dialog.show();
}
}
The call of the Dialog:
proceedButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// Perform action on click
message.setType(type);
message.setFromId(fromID);
message.setToId(toID);
message.setTypeId(typeID);
message.setTime(time);
message.setTitle(title);
message.setReceiptNo(receiptNo);
message.setNote(note);
RestClient.putBookingOnPallet(basic,message,context);
DialogBuilder.bookingConfirmationDialog(context);
/* Intent activityChangeIntent = new Intent( NewProductActivity.this,
NewProductActivity.class);
NewProductActivity.this.startActivity(activityChangeIntent);*/
}
});
I may be missing something but you could override onAttach in the DialogFragment class instead of passing the context in through the constructor.
#Override
public void onAttach(#NonNull Context context) {
super.onAttach(context);
}
In my app I have implemented this custom dialog (which has a fairly complex layout) by extending DialogFragment. I expect this dialog to pop up when I click a button in my layout. (Which I have successfully achieved). But the problem is that the dialog shows up in a janky manner.
My custom dialog class:
public class CustomizeDialog extends DialogFragment implements AdapterView.OnItemSelectedListener {
// field declarations go here
#NonNull
#Override
public Dialog onCreateDialog(#Nullable Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
LayoutInflater inflater = getActivity().getLayoutInflater();
View view = inflater.inflate(R.layout.customize_dialog, null);
builder.setView(view)
.setTitle("Customize")
.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
}
})
.setPositiveButton("Let's go!", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
Intent intent = new Intent();
intent.setAction("fromDialog");
intent.putExtra("ratio",getRatio(paperSizeSpinner.getSelectedItem().toString()));
if(isOrientationSpinnerVisible){
intent.putExtra("isCustom",false);
intent.putExtra("orientation",orientationSpinner.getSelectedItem().toString());
} else {
intent.putExtra("isCustom",true);
}
intentProvider.getIntent(intent);
}
});
widthEditText = view.findViewById(R.id.width_et);
heightEditText = view.findViewById(R.id.height_et);
widthEditText.setEnabled(false);
heightEditText.setEnabled(false);
paperSizeSpinner = view.findViewById(R.id.paper_size_spinner);
orientationSpinner = view.findViewById(R.id.orientation_spinner);
// ArrayList for populating paperSize spinner via paperSizeAdapter
ArrayList<String> paperSizes = new ArrayList<>();
paperSizes.add("A0");
paperSizes.add("A1");
paperSizes.add("A2");
paperSizes.add("A3");
paperSizes.add("A4");
paperSizes.add("A5");
paperSizes.add("Custom");
// ArrayList for populating orientation spinner via orientationAdapter
ArrayList<String> orientation = new ArrayList<>();
orientation.add("Portrait");
orientation.add("Landscape");
// arrayAdapters containing arraylists to populate spinners
ArrayAdapter paperSizeAdapter = new ArrayAdapter(getActivity(), android.R.layout.simple_spinner_dropdown_item, paperSizes);
ArrayAdapter orientationAdapter = new ArrayAdapter(getActivity(), android.R.layout.simple_spinner_dropdown_item, orientation);
paperSizeSpinner.setAdapter(paperSizeAdapter);
orientationSpinner.setAdapter(orientationAdapter);
paperSizeSpinner.setSelection(4);
paperSizeSpinner.setOnItemSelectedListener(this);
orientationSpinner.setOnItemSelectedListener(this);
return builder.create();
}
// These are some important complex ui functionalities
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
if (parent.getId() == R.id.paper_size_spinner) {
if (position == 6) {
widthEditText.setEnabled(true);
heightEditText.setEnabled(true);
orientationSpinner.setEnabled(false);
isOrientationSpinnerVisible = false;
} else {
widthEditText.setEnabled(false);
heightEditText.setEnabled(false);
orientationSpinner.setEnabled(true);
isOrientationSpinnerVisible = true;
}
}
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
}
// interface used to communicate with the parent activity
public interface IntentProvider {
// this method is used to provide the intent to the parent activity
void getIntent(Intent intent);
}
// instantiating the interface object and throwing error if parent activity does not implement this interface
#Override
public void onAttach(#NonNull Context context) {
super.onAttach(context);
try {
intentProvider = (IntentProvider) context;
} catch (ClassCastException e) {
throw new ClassCastException(context.toString() + " must implement IntentProvider");
}
}
}
MainActivity class:
public class MainActivity extends AppCompatActivity implements CustomizeDialog.IntentProvider {
// field declarations go here
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
imageView = findViewById(R.id.image);
// instantiating the dialog
final CustomizeDialog dialog = new CustomizeDialog();
findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// showing the dialog on click
dialog.show(getSupportFragmentManager(),"");
}
});
}
// via this method I receive the intent from the dialog
// I know intent might not be the best option for this function but let's let it be here for now
#Override
public void getIntent(Intent intent) {
ratio = intent.getFloatExtra("ratio",3);
isCustom = intent.getBooleanExtra("isCustom",false);
orientation = intent.getStringExtra("orientation");
launchChooser();
}
}
Let me know in the comments if you want the layout code for the dialog.
What I tried:
Implementing threading so that my dialog is ready in a background thread and show it onButtonClick. But this is not allowed in general as any other thread except UI thread aren't supposed to touch UI related events.
Using onCreateView instead of onCreateDialog to inflate the layout directly.
Making the dialog a global variable, initialized it in onCreate and then show the dialog onButtonClick.
Switched to CONSTRAINT LAYOUT
Using an activity as a dialog by setting the dialog theme to the activity in the manifest file.
Launched my app in a device with better hardware than mine.
BUT NOTHING WORKED
What I want:
Why is my dialog janky? and what I need to do to make the dialog pop up faster?
In case anybody wants here's the link to my app repo on github.
AlertDialog and DialogFragment frameworks are slow because they need to some time to do calculations and fragment stuffs. So a solution to this problem is, using the Dialog framework straight away.
Use the Dialog framework's constructor to initialize a Dialog object like this:
Dialog dialog = new Dialog(context, R.style.Theme_AppCompat_Dialog);
// the second parameter is not compulsory and you can use other themes as well
Define the layout and then use dialog.setContentView(R.layout.name_of_layout).
Use dialog.findViewById(R.id.name_of_view) to reference views from the dialog's layout file
And then implement the logic just like anyone would do in an activity class. Find out the best implementation for your use case by reading the official documentation.
I am attempting to pass data from my adapter to an activity with a dialog between them.
My current data flow is
RecyclerAdapter --> Confirmation Activity --> Chat Activity
What I want
RecyclerAdapter --> Custom Dialog --> Chat Activity
previously in my on click, I just had an intent to carry it over to the confirmation activity then to the chat activity but I am unable to do that now. I read on this post about using shared preferences but was unable to successfully implement it so I am wondering if there is a better way to go about it if i am missing any information pleas let me know and i will update it
adapter
public void openDialog(){
FragmentManager manager = ((AppCompatActivity)mContext).getSupportFragmentManager();
Confirmation_Dialog confirmation_dialog = new Confirmation_Dialog();
confirmation_dialog.show(manager, "example dialog");
}
dialog
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
LayoutInflater inflater = getActivity().getLayoutInflater();
View view = inflater.inflate(R.layout.layout_dialog, null);
builder.setView(view)
.setTitle("Are You Sure");
mYesBtn = view.findViewById(R.id.yes_button_dialog);
mNoBtn = view.findViewById(R.id.no_button_dialog);
mYesBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Toast.makeText(getContext(), "it worked YES!!", Toast.LENGTH_SHORT).show();
}
});
mNoBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
dismiss();
}
});
return builder.create();
}
}
Just use bundle to pass data to the new Activity.
In the adapter
String value="Hello world";
Intent i = new Intent(context, NewActivity.class);
i.putExtra("key",value);
startActivity(i);
Then in the new Activity, retrieve those values:
Bundle extras = getIntent().getExtras();
if (extras != null) {
String value = extras.getString("key");
//The key argument here must match that used in the other activity
}
Your dialog is FragmentDialog, you can use setArguments method to pass argument.
Don't use shared pref to pass data, shared pref is more like saving data in the phone for future reference. In this case (like #average_developer suggested) use Intent Bundles to pass data to the targeted activity.
I think in your case, you have to use (code below) to actually get some information to identify which chat it will be created in the following activity.
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int pos, long l) {
Intent i = new Intent(this, ProductActivity.class);
i.putExtra("item_id", manager.getItemIdAtIndex(pos));
startActivity(i);
}
You can create adapter click event in to activity class and make interface in to your adapter like below in your adapter do like:
onCircularsClick _oncircularClick;
public interface onCircularsClick {
public void _onCircularClick(Circular.TableBean bean);
}
your adapter constructor
public CircularListAdapter(Context ctx, onCircularsClick __oncircularClick) {
this.ctx = ctx;
this._oncircularClick = __oncircularClick;
}
and set click like
viewHolder.lin.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
_oncircularClick._onCircularClick(list.get(i));//data that you want to pass when click fires
}
});
and while setting adapter from your activity you can get this click event over there so can write code for click (open dialog ) in to activity class
Instead of having the dialog in a separate file I just moved it into the adapter class
I've created a custom dialog, which has multiple views within it.
On click of these Views, I would like to start activities for results, like Camera, Gallery, etc.
CustomDialog
public class CustomDialog extends BottomBaseDialog {
public static LinearLayout ll_camera;
public static LinearLayout ll_gallery;
public CustomDialog(Context context, View animateView) {
super(context, animateView);
}
#Override
public View onCreateView() {
View inflate = View.inflate(context, R.layout.dialog_custom, null);
ll_camera = ViewFindUtils.find(inflate, R.id.camera_linear_layout);
ll_gallery = ViewFindUtils.find(inflate, R.id.gallery_linear_layout);
return inflate;
}
#Override
public boolean setUiBeforShow() {
ll_camera.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// OPEN INTENT FOR CAMERA
dismiss();
}
});
ll_gallery.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// OPEN INTENT FOR GALLERY
dismiss();
}
});
return false;
}
}
Then within my fragment, I've displayed this dialog by
IOSTaoBaoDialog dialog = new IOSTaoBaoDialog(getActivity(), AddActivity.drawerLayout);
dialog.show();
How can I call onClick for the Camera and Gallery Linear Layout views from within my Fragment?
I also need to get the result of the activities back into the fragment, so I can process it.
Please suggest.
I've done a lot of search and I came across suggestions to use Interfaces, however, I do not clearly understand how that will work.
IOSTaoBaoDialog dialog = new IOSTaoBaoDialog(getActivity(), AddActivity.drawerLayout);
dialog.show();
Change To
IOSTaoBaoDialog dialog = new IOSTaoBaoDialog(getparent(), AddActivity.drawerLayout);
dialog.show();
If This Not Work Then Try
IOSTaoBaoDialog dialog = new IOSTaoBaoDialog(getActivity().getparent(), AddActivity.drawerLayout);
dialog.show();
OR
IOSTaoBaoDialog dialog = new IOSTaoBaoDialog(getparent().getActivity(), AddActivity.drawerLayout);
dialog.show();
For startActivityForResult()
IF(getparent() == null)
{
startActivityForResult();
}else
{
getparent().startActivityForResult();
}
You should be using DialogFragment, look at this answer. Here are the two important lines from that answer:
In calling Fragment:
dialog.setTargetFragment(this, YES_NO_CALL);
In DialogFragment:
getTargetFragment().onActivityResult(getTargetRequestCode(), Activity.RESULT_OK, null);
Basically, when you call the DialogFragment, you need to call setTargetFragment with a request code. Then in your fragment, you handle the response in onActivityResult.
I figured out the solution for this, for if somebody else also gets stuck in the same situation:
I passed the instance of my calling fragment to the dialog. Then from within the dialog, I called the fragment.startActivityForResult() method. So when the result was received, it was sent to the onActivityResult() method of the fragment.
The code is:
Dialog:
public class SelectApplicationDialog extends BottomBaseDialog {
public static LinearLayout ll_camera;
public static LinearLayout ll_gallery;
Fragment fragment;
public SelectApplicationDialog(Context context, View animateView, Fragment fragment) {
super(context, animateView);
this.fragment = fragment;
}
#Override
public View onCreateView() {
View inflate = View.inflate(context, R.layout.dialog_select_application, null);
ll_camera = ViewFindUtils.find(inflate, R.id.camera_linear_layout);
ll_gallery = ViewFindUtils.find(inflate, R.id.gallery_linear_layout);
return inflate;
}
#Override
public boolean setUiBeforShow() {
ll_camera.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
File externalStorageFile = new File(imagePath);
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
AddCourseFragment.imageUri = Uri.fromFile(externalStorageFile);
intent.putExtra(MediaStore.EXTRA_OUTPUT, AddCourseFragment.imageUri);
fragment.startActivityForResult(intent, 1);
dismiss();
}
});
ll_gallery.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent pickPhoto = new Intent(Intent.ACTION_PICK,
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
fragment.startActivityForResult(pickPhoto, 2);
dismiss();
}
});
return false;
}
}
Calling Fragment:
public void openUploadImageDialog() {
SelectApplicationDialog dialog = new SelectApplicationDialog(getContext(),
AddActivity.addLinearLayout, AddCourseFragment.this);
dialog.show();
}
Before referring me to other threads on this forum and marking my question as duplicate kindly read my question. I have to create a global application timeout. No matter which activity is user on, after specific amount of time the user will be displayed AlertDialog that his session has expired and he can exit or renew his session. I have read different solutions and used service as my solution.
public class InActivityTimer extends Service {
MyCounter timer;
#Override
public void onCreate() {
timer = new MyCounter(20 * 1000,1000);
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
timer.start();
return super.onStartCommand(intent, flags, startId);
}
private class MyCounter extends CountDownTimer{
public MyCounter(long millisInFuture, long countDownInterval) {
super(millisInFuture, countDownInterval);
}
#Override
public void onFinish() {
Intent intent = new Intent("timeout_action");
sendBroadcast(intent);
stopSelf();
}
#Override
public void onTick(long millisUntilFinished) {
// Need AlertDialog code here
Toast.makeText(getApplicationContext(), ("Time Remaining: " + millisUntilFinished/1000)+"", Toast.LENGTH_SHORT).show();
}
}
#Override
public void onDestroy() {
timer.cancel();
super.onDestroy();
}
#Override
public IBinder onBind(Intent arg0) {
return null;
}
}
The problem is that I can display the Toast without any problem but the AlertDialog is not displayed when called inside onFinish().
The first problem is to display the AlertDialog for whole application bearing in mind that the AlertDialog is displayed for some context. Also if somehow the AlertDialog is displayed then how to close the Application. On Activity I just close the activity by calling finish() so should I clear the Activities stack in this case?
The second complex part that I am facing is to display a popup when user click "Time remaining" link in the application which will show how much time is remaining for the Session to be timed out. This time should be exactly same as the time remaining in the service.
I can also use BroadcastReceiver and send update to the activity once the time is finished but wouldn't that be Activity specific because I want the timeout to act same regardless of which activity is user on. I want to avoid writing the same code on each activity.
Kindly guide me through with some solution.
If you use a fragment based design for your app, you can keep a root FragmentActivity in which all other elements of the app are displayed. This way you can use the context of the root FragmentActivity every time, to display your Dialog.
Additional: "Could you kindly refer to me some article.."
What you are doing is not common, and I would have to google search just like you to find any existing example similar to your case. I can however fill in a bit more detail on what I have proposed above.
If you are unfamiliar with using Fragments, read the Developer Documentation.
public class MainActivity extends FragmentActivity {
private static final int SPLASH_SCREEN_FRAGMENT = 0;
private static final int HOME_SCREEN_FRAGMENT = 1;
...
#Override
protected void onCreate(Bundle. savedInstanceState) {
super.onCreate(savedInstanceState);
// show your first fragment
Fragment splashFragment = new SplashFragment();
getSupportFragmentManager().beginTransaction().replace(android.R.id.content, splashFragment).commit();
// Start your service using the context of your FragmentActivity
// Your FragmentActivity will always be the current activity, and you will display
// all other elements of your app inside it as fragments
Intent intent = new Intent(this, InActivityTimer.class);
startService(intent);
}
// method for switching the displayed fragment
private void fragmentSwitcher(int fragmentType) {
Fragment currentFragment = new Fragment();
switch (currentFragmentType) {
case SPLASH_SCREEN_FRAGMENT:
currentFragment = new SplashScreenFragment();
break;
case HOME_SCREEN_FRAGMENT:
currentFragment = new HomeScreenFragment();
break;
...
}
getSupportFragmentManager().beginTransaction().replace(android.R.id.content, currentFragment).commit();
}
}
I have solved my issue with rather very simple approach.
#Override
public void onFinish() {
Intent intent = new Intent(getBaseContext(), TimeoutActivity.class);
startActivity(intent);
stopSelf();
}
and below is the onCreate method for my TimeoutActivity.
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ContextThemeWrapper ctw = new ContextThemeWrapper(TimeoutDialogActivity.this, R.style.Theme_Base_AppCompat_Dialog_FixedSize);
final AlertDialog alertDialog = new AlertDialog.Builder(ctw).create();
alertDialog.setCancelable(false);
alertDialog.setTitle("Session Timeout !");
alertDialog.setTitle("Your session has expired.");
alertDialog.setButton(AlertDialog.BUTTON_NEGATIVE, "Logout", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
alertDialog.dismiss();
finish();
}
});
alertDialog.setButton(AlertDialog.BUTTON_NEUTRAL, "Exit", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
alertDialog.dismiss();
finish();
}
});
alertDialog.setButton(AlertDialog.BUTTON_POSITIVE, "Renew Session", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
alertDialog.dismiss();
finish();
});
alertDialog.show();
}