Can an Android Fragment overlaying the PhoneGap Activity? - java

The following image should represent an PhoneGap/Cordova app which is marked in blue.
The red area should be an Android Fragment.
Is it possible tho have an Android Fragment which overlays a PhoneGap Activity?
Edit: The overlaying Android Fragment should the tasks like image manipulation.
How do I have to write a PhoneGap plugin that communicates with the Fragment?

the way i did this was by writing a plugin that shows a custom dialog without border, background shadow, etc.
my execute() method looks like this:
#Override
public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
if (resources == null)
resources = cordova.getActivity().getApplication().getResources();
if (package_name == null)
package_name = cordova.getActivity().getApplication().getPackageName();
if (inflator == null) {
inflator = cordova.getActivity().getLayoutInflater();
}
if (action.equals("show")) {
this.show(args, callbackContext);
return true;
}
return false; // Returning false results in a "MethodNotFound" error.
}
and the show() method contains something like this:
[...]
Runnable runnable = new Runnable() {
public void run() {
pinpad = new Dialog(cordova.getActivity());
pinpad.requestWindowFeature(Window.FEATURE_NO_TITLE);
Window window = pinpad.getWindow();
window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
WindowManager.LayoutParams wlp = window.getAttributes();
wlp.gravity = Gravity.BOTTOM;
window.setAttributes(wlp);
pinpad.setCancelable(false);
pinpad.setContentView(view);
pinpad.getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT, (int) height);
pinpad.show();
}
};
this.cordova.getActivity().runOnUiThread(runnable);
[...]
if your window (the red part) has to be placed in some particular position (not in the center or at the bottom of the screen) then you have to pass coordinates from javascript to native plugin.

Related

Toolbar dissapears from custom hover in eclipse editor

I am working on an editor plugin for Eclipse that handles my own script language. In the editor, I have a hover that shows short information about element under the mouse cursor.
Now, I am trying to create a toolbar on the bottom of the hover and place a button there that will open a more detailed description online.
I have written my code based on answer to that question. The button is visible and it works when it is clicked.
However, it disappears a short time after I move my mouse over the hover. Why is this happening and how can I prevent that?
Here is the relevant part of my code:
#Override
public IInformationControlCreator getHoverControlCreator() {
return new IInformationControlCreator() {
#Override
public IInformationControl createInformationControl(final Shell parent) {
ToolBarManager tbm = new ToolBarManager(SWT.FLAT);
DefaultInformationControl defaultInformationControl = new DefaultInformationControl(parent, tbm);
Action action = new Action() {
#Override
public void run() {
MessageDialog.openInformation(parent, "omg", "It works.");
}
};
action.setText("123 test 321");
Bundle bundle = FrameworkUtil.getBundle(this.getClass());
URL url = FileLocator.find(bundle, new Path("icons/test.gif"), null);
action.setImageDescriptor(ImageDescriptor.createFromURL(url));
tbm.add(action);
tbm.update(true);
return defaultInformationControl;
}
};
}
When hover is created with DefaultInformationControl(parent, tbm) then toolbar is visible. However when you move mouse over the hover, then it gains focus. Then method getInformationPresenterControlCreator() from DefaultInformationControl is called.
It looks like (from source code):
public IInformationControlCreator getInformationPresenterControlCreator() {
return new IInformationControlCreator() {
/*
* #see org.eclipse.jface.text.IInformationControlCreator#createInformationControl(org.eclipse.swt.widgets.Shell)
*/
public IInformationControl createInformationControl(Shell parent) {
return new DefaultInformationControl(parent,
(ToolBarManager) null, fPresenter);
}
};
}
Look at return line. It nulls your Toolbar manager. That is the reason is gone.
Quick solution might be to create a new class which extends DefaultInformationControl and then in overrides
#Override
public IInformationControlCreator getInformationPresenterControlCreator() {
return new YourOwnInformationControlCreator();
}
This way you can pass correct ToolbarManager.

how to implement borders around menuitem in SwipeMenuListView

I am using the library com.baoyz.swipemenulistview every thing is working good i want borders around each menu items, so that even if all menu item background is white a grey border is around the each item separating each other.
After looking into the code i have found that this can be implemented in following function of SwipeMenuView.java
private void addItem(SwipeMenuItem item, int id) {
LayoutParams params = new LayoutParams(item.getWidth(),
LayoutParams.MATCH_PARENT);
LinearLayout parent = new LinearLayout(getContext());
parent.setId(id);
parent.setGravity(Gravity.CENTER);
parent.setOrientation(LinearLayout.VERTICAL);
parent.setShowDividers(LinearLayout.SHOW_DIVIDER_BEGINNING);
parent.setLayoutParams(params);
parent.setBackgroundDrawable(item.getBackground());
parent.setOnClickListener(this);
addView(parent);
if (item.getIcon() != null) {
parent.addView(createIcon(item));
}
if (!TextUtils.isEmpty(item.getTitle())) {
parent.addView(createTitle(item));
}
}
As i am newbie for android world, i am unable to find the way to to draw border around menu item. Which function/method to look for in LinearLayout that have the capability to draw borders. Or how to draw border as shown
Ide : Android Studio 2.2.3
Link to library :
SwipeMenuListView Github
UPDATE
I have added GradeintDrawable to the function now border is there but here i cannot pass item.getBackground which will return (Drawable). How to set GradientDrawable.setColor (int color); with item.getBackground which will return Drawable;
private void addItem(SwipeMenuItem item, int id) {
LayoutParams params = new LayoutParams(item.getWidth(),
LayoutParams.MATCH_PARENT);
GradientDrawable drawable = new GradientDrawable();
drawable.setShape(GradientDrawable.RECTANGLE);
drawable.setStroke(1, Color.BLACK);
drawable.setCornerRadius(1);
//drawable.setColor(Color.GRAY); here i have to pass item.getBackground();
//like :
drawable.setColor(item.getBackground); //error because getBackground is of type drawable;
LinearLayout parent = new LinearLayout(getContext());
parent.setId(id);
parent.setGravity(Gravity.CENTER);
parent.setOrientation(LinearLayout.HORIZONTAL);
parent.setLayoutParams(params);
//parent.setBackgroundDrawable(item.getBackground());
parent.setBackgroundDrawable(drawable);
parent.setOnClickListener(this);
addView(parent);
if (item.getIcon() != null) {
parent.addView(createIcon(item));
}
if (!TextUtils.isEmpty(item.getTitle())) {
parent.addView(createTitle(item));
}
}

Load media thumbnails efficiently

I've spent few days to solve this problem but still can't find a solution. I'm new to Android so my code might be pretty messy!
I have a RecyclerView(Grid layout) that displays thumbnails for images and videos. It loads media files in a specific folder. But when I launch this activity, it takes up so much memory!
To load thumbnails, I created two threads.
Thread 1) MediaLoadThread that queries media files in SDCard. It loops through the cursor and queue thumbnail decode tasks to the different thread.
Thread 2) ThumbnailLoaderThread that decode each individual thumbnail. It receives the content resolver, media type(image or video), and media id. It uses basic .getThumbnail() method. After it's done with getting thumbnail, it triggers the response callback to it's caller thread(MediaLoadThread).
3) When MediaLoadThread(Thread 1) receives the callback, it triggers another callback that lets the activity update the adapter item of the given position. The adapter updates the UI and finally the thumbnail ImageView changes from placeholder to actual thumbnail.
:::Here's my code:::
1) MediaLoadThread.java
#Override
public void run() {
mMediaDataArr.clear();
mLoaderThread.start(); // Prepping the thread 2
mLoaderThread.prepareHandler();
// .... SD Card query stuff .....
if (mediaCursor != null && mediaCursor.moveToFirst()) {
do {
mMediaDataArr.add(new MediaData(videoCursor.getInt(columnIndexId),
mediaCursor.getLong(columnIndexDate), //ID
mediaCursor.getInt(columnIndexType), //MEDIA TYPE
null); //THUMBNAIL BITMAP (NULL UNTIL THE ACTUAL THUMBNAIL IS DECODED)
} while (mediaCursor.moveToNext());
mediaCursor.close();
mResponseHandler.post(new Runnable() {
#Override
public void run() {
// This callback lets the activity activate the adapter and recyclerview so that the user can interact with recyclerview before the app finishes decoding thumbnails.
mCallback.onVideoLoaded(mMediaDataArr);
}
});
//Passing tasks to thread 2
for (int i = 0; i < mMediaDataArr.size(); i++) {
mLoaderThread.queueTask(
mMediaDataArr.get(i).getmMediaType(),
i, mMediaDataArr.get(i).getmMediaId());
}
}
}
}
// This is triggered by thread 2 when it finishes decoding
#Override
public void onThumbnailLoaded(final int position, final Bitmap thumbnail) {
mResponseHandler.post(new Runnable() {
#Override
public void run() {
mCallback.onThumbnailPrepared(position, thumbnail);
}
});
}
2) ThumbnailLoaderThread.java
public void queueTask(int mediaType, int position, int videoId) {
mWorkerHandler.obtainMessage(mediaType, position, videoId).sendToTarget();
}
public void prepareHandler() {
mWorkerHandler = new Handler(getLooper(), new Handler.Callback() {
#Override
public boolean handleMessage(Message msg) {
int type = msg.what;
final int position = msg.arg1;
int videoId = msg.arg2;
try {
if (type == MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE) {
Bitmap newThumb = MediaStore.Images.Thumbnails
.getThumbnail(mCr, videoId,
MediaStore.Images.Thumbnails.MINI_KIND, null);
postResult(position, newThumb);
} else if (type == MediaStore.Files.FileColumns.MEDIA_TYPE_VIDEO) {
Bitmap newThumb = MediaStore.Video.Thumbnails
.getThumbnail(mCr, videoId,
MediaStore.Video.Thumbnails.MINI_KIND, null);
postResult(position, newThumb);
}
} catch (Exception e) {
e.printStackTrace();
}
return true;
}
});
}
private void postResult(final int position, final Bitmap newThumb) {
mResponseHandler.post(new Runnable() {
#Override
public void run() {
mCallback.onThumbnailLoaded(position, newThumb);
}
});
}
3) LibraryActivity.java
#Override
public void onThumbnailPrepared(int position, Bitmap thumbnail) {
if (thumbnail != null && position < mData.size()) {
MediaData updatedData = mData.get(position);
updatedData.setmThumbnail(thumbnail);
mData.set(position, updatedData);
mVideoAdapter.notifyItemChanged(position);
}
}
The flow is like this.
1) The activity starts the thread 1.
2) Thread 1 starts querying files and starts thread 2. It passes the media id looping through the cursor.
3) Thread 2 decodes thumbnails with the given media id.
4) When decoding is done, thread 2 triggers the callback to Thread 1 with the result bitmap.
5) Thread 1 receives the bitmap and delivers the bitmap to activity through callback.
6) Activity receives the thumbnail and updates the RecyclerView data with the given bitmap.
It works fine, but when the system allocates almost 50MB of memory for this task... Considering it was only loading 100 thumbnails, I think it's pretty heavy.
:::What I've tried:::
1) I extracted the URI of each individual thumbnail and let the recyclerview adapter to load the image with the given URI when it binds. It works fine and did not consume that much memory, but because it loads images when the item is bound, it reloads the thumbnail whenever I scroll the screen with a little bit of delay.
2) I let the adapter to load thumbnails with the direct thumbnail path. But it won't work when the user cleans up the /.thumbnails folder.
3) I set the BitmapFactory.Options samplsize into 4 when the thread decodes thumbnails. But when it was still heavy and even slower sometimes...
4) In MediaData object, it holds the thumbnail bitmap as a member variable. So I made it null right after the adapter loaded it into the ImageView. Still heavy, and because I made the object's thumbnail into null, it just shows the placeholder when I scroll back.
I really have no clue. Any help would be appreciated!!
You can used nostra universal image loader library to load images. This library is very good for image loading and also some other library like Picasso, glide etc available which you can used instead of making manual coding.

How do I dynamically set the visibility of the SideMenuBar in Codename one?

Using the Toolbar class within codenameone, how do I dynamically set the visibility of the SideMenuBar?
I'm using a WebBrowser component, and I only want the SideMenu to be accessible after login.
I achieved the behavior I wanted when I was simply placing commands on a SideMenuBar (METHOD 1), but now that I've switched over to use the Toolbar class for the LnF advantages (METHOD 2), the hideLeftSideMenuBool theme constant does not seem to be observed.
//METHOD 1
//CHANGING THE THEME DYNAMICALLY HIDES THE SIDEMENUBAR WHEN I'VE SIMPLY
//ADDED COMMANDS LIKE THIS
current.addCommand(new Command("Home") {
{
putClientProperty("place", "side");
}
});
//METHOD 2
//CHANGING THE THEME DYNAMICALLY DOES NOT HIDE THE SIDEMENUBAR WHEN I'VE
//USED toolbar.addComponentToSideMenu TO ADD BUTTONS WITH COMMANDS
toolbar = new Toolbar();
current.setToolbar(toolbar);
Button home = new Button("Home");
toolbar.addComponentToSideMenu(home, new Command("Home"){
#Override
public void actionPerformed(ActionEvent evt) {
wb.setURL(startURL);
}
});
...
//I USED THE FOLLOWING CODE TO DYNAMICALLY SET THE THEME AFTER EVALUATING A
//WebBrowser URI REGARDLESS OF WHICH METHOD WAS USED TO ADD COMMANDS
wb.setBrowserNavigationCallback(new BrowserNavigationCallback() {
public boolean shouldNavigate(String url) {
if ((url.indexOf("users/login") != -1)) {
try {
//theme_noside.res has hideLeftSideMenuBool set to true
theme = Resources.openLayered("/theme_noside");
UIManager.getInstance().setThemeProps(theme.getTheme(theme.getThemeResourceNames()[0]));
UIManager.getInstance().getLookAndFeel().setMenuBarClass(SideMenuBar.class);
Display.getInstance().setCommandBehavior(Display.COMMAND_BEHAVIOR_SIDE_NAVIGATION);
current.refreshTheme();
}catch(IOException e){
Log.p(e.toString());
}
}
else {
try {
//theme.res has hideLeftSideMenuBool set to false
theme = Resources.openLayered("/theme");
UIManager.getInstance().setThemeProps(theme.getTheme(theme.getThemeResourceNames()[0]));
UIManager.getInstance().getLookAndFeel().setMenuBarClass(SideMenuBar.class);
Display.getInstance().setCommandBehavior(Display.COMMAND_BEHAVIOR_SIDE_NAVIGATION);
current.refreshTheme();
}catch(IOException e){
Log.p(e.toString());
}
}
return true;
}
});
Use Toolbar api only and you don't have to call or change any theme constant.
Make your toolbar final or declare it outside the beforeShow() method, so you can access it within inner method shouldNavigate(String url).
All you need to do is call removeAll() and then reset the title and add components you want. If toolbar has no command or title, it would be hidden by default.
wb.setBrowserNavigationCallback(new BrowserNavigationCallback() {
public boolean shouldNavigate(String url) {
if ((url.indexOf("users/login") != -1)) {
toolbar.removeAll();
toolbar.setTitleComponent(new Label("My Form", "Title"));
toolbar.getComponentForm().revalidate();
} else {
//Do nothing, since I've already add the commands I want earlier
}
return true;
}
});

Override single tap of Photoview

I have an ImageView inside of a view pager with an ActionBar at the top. I would like to be able to single tap to hide the action bar, and I would also like to be able to pinch zoom and pan on each ImageView.
To implement the single tap to hide the action bar I have a simple OnClickListener that hides it.
To implement the pinch zoom and pan on each ImageView I am using the PhotoView Library Project.
I am having issues because only one touch event listener can be associated with an ImageView, and the implementing the PhotoView Library project overwrites my OnClickListener to hide the ActionBar with,
parent.requestDisallowInterceptTouchEvent(true);
I am not sure how to go about getting both implemented at the same time. It seems like the only solution is to create my own Pinch Zoom ImageView in order to control touch events myself.
Found out that the PhotoView library actually allows me to set onViewTap for the PhotoViewAttacher object which is exactly what I wanted.
To create the PhotoViewAttacher in the current Fragment/Activity have it implement PhotoViewAttacher.OnViewTapListener, create the attacher,
PhotoViewAttacher mAttacher = new PhotoViewAttacher(imageView);
mAttacher.setOnViewTapListener(this);
and add the following function,
public void onViewTap(View view, float x, float y) {
// your code here
}
Source
You'll have to override the PhotoView library itself. If you look at the source code, the PhotoViewAttacher class is the one that handles the onTouch events.
You'll have to add the special funcionality you're looking for at this part of the code (specially, the ACTION_DOWN) event:
#Override
public final boolean onTouch(View v, MotionEvent ev) {
boolean handled = false;
if (mZoomEnabled && hasDrawable((ImageView) v)) {
ViewParent parent = v.getParent();
switch (ev.getAction()) {
case ACTION_DOWN:
// First, disable the Parent from intercepting the touch
// event
if (null != parent)
parent.requestDisallowInterceptTouchEvent(true);
else
Log.i(LOG_TAG, "onTouch getParent() returned null");
// If we're flinging, and the user presses down, cancel
// fling
cancelFling();
break;
case ACTION_CANCEL:
case ACTION_UP:
// If the user has zoomed less than min scale, zoom back
// to min scale
if (getScale() < mMinScale) {
RectF rect = getDisplayRect();
if (null != rect) {
v.post(new AnimatedZoomRunnable(getScale(), mMinScale,
rect.centerX(), rect.centerY()));
handled = true;
}
}
break;
}
// Check to see if the user double tapped
if (null != mGestureDetector && mGestureDetector.onTouchEvent(ev)) {
handled = true;
}
if (!handled && null != parent) {
parent.requestDisallowInterceptTouchEvent(false);
}
// Finally, try the Scale/Drag detector
if (null != mScaleDragDetector
&& mScaleDragDetector.onTouchEvent(ev)) {
handled = true;
}
}
return handled;
}

Categories

Resources