I am working on making custom launcher in android. I have referred the code of android's Jellybean launcher. now I want to make some modification in this launcher.
What I want : As we know there are default five work-space screens and I want to add custom view in any one of the workspace screen. My xml file should be inflated in any one of the screen.
I have tried many ways to do it but as the default launcher code is very complex still having no luck to finding out way for it.
There is already app named SOHO in Playstore doing exactly what I want. I have add the screenshot for referencing what i want.
Please help me if anyone of you having any idea to do it.
I've the answer for you. You can do it both in Launcher2 and Launcher3 package from (AOSP). Jellybean is using Launcher2 may be. I personally suggest you to go with Launcher3, it has buit-in way to do so.
Launcher3:
create a class that extends the com.android.launcher3.Launcher class and override the necessary methods like so:
public class MyLauncher extends Launcher {
#Override
protected boolean hasCustomContentToLeft() {
return true;
}
#Override
protected void addCustomContentToLeft() {
View customView = getLayoutInflater().inflate(R.layout.custom, null);
CustomContentCallbacks callbacks = new CustomContentCallbacks() {
#Override
public void onShow() {}
#Override
public void onScrollProgressChanged(float progress) {}
#Override
public void onHide() {}
};
addToCustomContentPage(customView, callbacks, "custom view");
}
}
Here R.layout.custom is the custom view that you wanted.
Then in the manifest file change the launcher activity class from Launcher to MyLauncher. And that's it.
Launcher2:
in Workspace.java create the following method:
public void addCustomView(View child){
CellLayout layout = (CellLayout) getChildAt(0);
layout.addView(child);
}
then in Launcher.java, find the following line:
mWorkspace = (Workspace) mDragLayer.findViewById(R.id.workspace);
then paste the following code somewhere after that line:
View child = LayoutInflater.from(this).inflate(R.layout.custom, null);
mWorkspace.addCustomView(child);
If I remember correctly you just need to implement a standard activity which displays a home launcher. In your Manifest.xml you just need to define it like this:
<activity android:name=".YourLauncher" android:label="#string/launcher_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
you can simply add view in default lanucher use code
wm = (WindowManager) getSystemService("window");
params = new LayoutParams();
params.type = LayoutParams.TYPE_PHONE;
params.format = PixelFormat.RGBA_8888;
params.flags = LayoutParams.FLAG_NOT_TOUCH_MODAL
| LayoutParams.FLAG_NOT_FOCUSABLE;
params.x = 100;
params.y = 100;
params.height = WindowManager.LayoutParams.WRAP_CONTENT;
params.width = WindowManager.LayoutParams.WRAP_CONTENT;
params.gravity = Gravity.LEFT | Gravity.TOP;
wm.addView(view, params);
when you want to remove it
just
wm.removeView(v);
you also need permission
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
Good news, not so good news, bad news. Good new first.
It is possible to do what you want.
Now the not so good news.
You will have to write the launcher application from scratch(aka Home Screen). Yep, that involves doing all those nice and nifty things that the default launcher does(multiple pages, drag and drop, delete/add app icons, etc). Fortunately, its not as difficult as it sounds. Because the default launcher app itself is opensource. Though this code is complete, its not easy to read. A easier place to start would be the SDK
Android-SDK/samples/android-x/Home/
where x is the API level.
They have provided source code for an example home screen and it should give you a good start. With some perseverance and coffee, you should be able to modify the Launcher2 code to add a customized page of your own.
Now the Hard part.
Because a part of your goal is to keep the existing pages same and add a new page, getting this to work for all the flavors of android... HTC sense, Samsung TouchWiz, etc, etc is not a single person workload. They all have different features for the Home screen. Preserving these features and adding a new customized page is a tough task.
Related
I created a sample app using JieCao player for android and it works perfectly fine both on portrait and landscape mode (on pressing expand button). But when I tried to integrate the same for the another app that I'm creating I get a black screen on pressing the video expand button but the audio is playing in the background. Couldn't get the reason why this is happening !! I have explained the code that I'm working on below :
Mainactivity.java
jcVideoPlayerStandard = (JCVideoPlayerStandard) findViewById(R.id.custom_videoplayer_standard);
jcVideoPlayerStandard.setUp("http://2449.vod.myqcloud.com/2449_bfbbfa3cea8f11e5aac3db03cda99974.f20.mp4","");
ImageLoader.getInstance().displayImage("http://p.qpic.cn/videoyun/0/2449_bfbbfa3cea8f11e5aac3db03cda99974_1/640",jcVideoPlayerStandard.thumbImageView);
activity_main.xml
<fm.jiecao.jcvideoplayer_lib.JCVideoPlayerStandard
android:id="#+id/custom_videoplayer_standard"
android:layout_width="match_parent"
android:layout_marginTop="55dp"
android:layout_height="250dp" />
And a separate java file that I include in AndroidManifest file though I'm pretty much sure it has nothing to do with the error. Here is the code :
public class VideoApplication extends Application {
#Override
public void onCreate() {
super.onCreate();
LeakCanary.install(this);
initUniversalImageLoader();
}
private void initUniversalImageLoader() {
ImageLoaderConfiguration.Builder config = new ImageLoaderConfiguration.Builder(getApplicationContext());
config.threadPriority(Thread.NORM_PRIORITY - 2);
config.denyCacheImageMultipleSizesInMemory();
config.diskCacheFileNameGenerator(new Md5FileNameGenerator());
config.diskCacheSize(50 * 1024 * 1024); // 50 MiB
config.tasksProcessingOrder(QueueProcessingType.LIFO);
config.writeDebugLogs(); // Remove for releaseAllVideos app
config.defaultDisplayImageOptions(getDefaultDisplayImageOption());
// Initialize ImageLoader with configuration.
ImageLoader.getInstance().init(config.build());
}
public static DisplayImageOptions getDefaultDisplayImageOption() {
DisplayImageOptions options = new DisplayImageOptions.Builder()
.showImageOnLoading(new ColorDrawable(Color.parseColor("#f0f0f0")))
.resetViewBeforeLoading(true)
.cacheInMemory(true)
.cacheOnDisk(true)
.considerExifParams(true)
.imageScaleType(ImageScaleType.EXACTLY_STRETCHED)
.bitmapConfig(Bitmap.Config.RGB_565)
.displayer(new FadeInBitmapDisplayer(500))
.build();
return options;
}}
If there is anything else needed please let me know, I just want to know where I am going wrong.
Note : People with higher reputation please create a tag "JieCao-player" which might be useful while creating a question related to this category. As I don't have enough reputation, kindly do the needful.
Just need to make sure that "android:hardwareAccelerated" is set to true in all the activities in Manifest file. By doing so the problem got resolved.
I am developing an app for commercial use with a background service that is getting transponder numbers (of animals) from an RFID reader via bluetooth.
After processing the received number I would like to send it to the clipboard and paste it in the focused text field of whatever application is currently in front which in my case is a browser app.
I already found a similar question from 2013 but with no accepted answer by now. All answers to the question just explained how to use ClipboardManager to copy and paste code within the developed application but that has not been meant by the problem as he clarified in a comment.
The simplest scenario that I could imagine is to just simulate a paste action on the android device. I would prefer not to need to install a third party app.
Just to add to Kirill's answer and assuming the app has Accessibility permission,
Create a class extending AccessibilityService and override onAccessibilityEvent method.
public class SampleAccessibilityService extends AccessibilityService {
#Override
public void onAccessibilityEvent(AccessibilityEvent accessibilityEvent) {
AccessibilityNodeInfo source = accessibilityEvent.getSource();
if (source != null) {
AccessibilityNodeInfo rowNode = getRootInActiveWindow();
if (rowNode != null) {
for (int i = 0; i < rowNode.getChildCount(); i++) {
AccessibilityNodeInfo accessibilityNodeInfo = rowNode.getChild(i);
if (accessibilityNodeInfo.isEditable() && accessibilityNodeInfo.isFocused()) {
accessibilityNodeInfo.performAction(AccessibilityNodeInfoCompat.ACTION_PASTE);
return;
}
}
}
}
}
#Override
public void onInterrupt() {
}
}
accessibilityNodeInfo.performAction(AccessibilityNodeInfoCompat.ACTION_PASTE) will paste the text that is copied to clipboard.
Also make sure you have right accessibility configuration.
config.xml
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
android:accessibilityFlags="flagDefault"
android:accessibilityEventTypes="typeViewClicked|typeViewFocused"
android:accessibilityFeedbackType="feedbackGeneric"
android:notificationTimeout="0"
android:canRetrieveWindowContent="true"
android:description="#string/testing" />
Here android:accessibilityEventTypes="typeViewClicked|typeViewFocused" will filter the events to view click or view focus.
You can also the events based on the packages using "android:packageNames" (so that your service won't get called often)
Finally declare the service in manifest,
<service android:name=".SampleAccessibilityService"
android:label="#string/app_name"
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/config" />
</service>
If you want your app to interact with an app that isn't yours (the browser) you will have to give this app accessibility permissions. those are special kind of permission that allow apps to interact with something that is a bit more senstive.
there are accessibility actions, the one that you are looking for is the
AccessibilityNodeInfoCompat.ACTION_PASTE it allows you to preform a paste into a focused field.
Note that I'd recommend you to replace the browser with a inapp WebView, and inject the values with javascript this will be much more robust solution for your automation. you can find more info on how to run JS on a webview here: How to get return value from javascript in webview of android?
My app crashec when rotating the device. I know it crashes because whenI rotate the screen it tries to create new View to draw and display but how can it create the view and display it properly on the launch but crashes when trying to create the second new view?
I dont know what part of my code I should post here? Can you give a clue to solve this problem?
I found something usefull. I put try/catch statement and now when I rotate the device, it doesnt crash but displays a blank page, when I re-rotate to the old position it display the page. here is my code
#Override
protected void onCreate(Bundle savedInstanceState) {
try{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());
mViewPager = (ViewPager) findViewById(R.id.pager);
mViewPager.setAdapter(mSectionsPagerAdapter);
} catch (Exception e) {
Log.i("my_error", e.getMessage());
}
}
but eclipse cannot catch the exception.
How can I solve this problem?
There are two possible ways to do this:
1) You don't care about the orientation change of the screen and you just want to be "resized". Just add the following properties in your Manifest file:
<activity
android:name=".SplashScreen"
android:configChanges="orientation|keyboardHidden|screenSize" ... />
and add this lines of code in your activity:
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// do nothing, just override
}
2) You do care about the orientation change. Then there are a couple of things that you should know about the activity lifecycle in an orientation change.
Firstly the onConfigurationChanged() is called and you should store in a Bundle everything that you need. For example the user has editted an EditText and you should save the value.
Why to do that? Because afterwards the onCreate() method will be called again in order for you to implement a different layout or alter something in the Views. You should then take the previously saved Bundle and restore the variables that you saved in your newly created layout.
Just add the android:configChanges="orientation" to your activity
<activity android:name=".MyActivity"
android:configChanges="orientation"/>
if you given like this, then oncreate will not called if your screen orientation is changed.
If you need more information about this you can check this link
There are a couple of things you can do:
1) Ignore screen orientation changes. If your app is only designed for portrait mode, most likely it won't look good in landscape mode and vice versa. Best is to specify the target orientation in your activities.
2) If you want to allow orientation changes, then you should have written some code re-create the view with different/modified layout. Mind sharing the code with us?
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
//Override this and recreate your view or set adapter here
}
Dont forget to add android:configChanges="orientation" in your manifest.
On a side note you can fix orientation through manifest like this -
android:screenOrientation="portrait"
Add this to your Activity tag in the manifest:
android:configChanges="orientation|screenSize"
This will cause that the activity is not recreated on rotation change.
The flag sreenSize is for newer devices(API level 13 or higher), with including only the orientation flag the activity will stil recreate when rotating on devices running API level 13 or higher.
I'm reading an android guide and I've arrived on a point where it explains the tag and it says that typing
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER">
I make my activity be the main activity.
My question is the following: is it possible to make the same thing in my source code just like in java typing something (public void main(...)) in such a way that my compiler understands that is my main activity?
The second question is quite general, is it possible to make everything done in xml just using my source file?
Intent filters
Intent filters are used by the system to try to find installed application components that can receive an intent that the system is trying to resolve, i.e. when the Intent doesn't specify a particular component class to target. For example, if you did this...
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivity(intent);
The system has no explicit indication what Activity (or Service, or BroadcastReceiver) to start. It has to find some components that are capable of resolving the Intent, and it uses the declared <intent-filter>s to do this. Typically an app that is capable of capturing an image (like the Camera app) will declare their activity handles this action.
When you click the launcher icon of your app, the launcher basically creates an Intent like this:
Intent mainIntent = new Intent(Intent.ACTION_MAIN);
mainIntent.setCategory(Intent.CATEGORY_LAUNCHER);
mainIntent.setPackage(/* your package */);
startActivity(mainIntent);
The result is the system tries to find a component in that package with an <intent-filter> that specifies <action android:name="android.intent.action.MAIN" /> and <category android:name="android.intent.category.LAUNCHER">.
In short, it has absolutely nothing to do with the presence of the typical public static void main() in Java.
XML
When the system loads an XML file at runtime (like a layout file), it is actually going to create Java objects based on the information it finds by parsing the file. Using layouts as an example, all the different XML tags (e.g. <ImageView>) have corresponding java classes (android.widget.ImageView), and most of the properties you can set with XML attributes can also be set using the public methods on those Views.
If you were so inclined, you could build your Activity's layout entirely in Java by instantiating them yourself and using the set[Property]() methods, which is essentially what the system is doing for you:
public void onCreate(Bundle saved) {
super.onCreate(saved);
LinearLayout layout = new LinearLayout(this);
layout.setPadding(20, 20, 20, 20);
layout.setOrientation(LinearLayout.VERTICAL);
TextView text = new TextView(this);
text.setTextSize(18);
text.setTextColor(Color.MAGENTA);
text.setText(R.string.hello_world);
layout.addView(text, LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
setContentView(layout);
}
Similar things happen with XML drawables, although creating them in Java is quite a bit different.
In short, many of the things you can do in XML you can also do in Java, but there are downsides to it though (you lose the automatic resource handling that the OS provides, for instance).
1、No
2、The Android.manitest File is a description file that tell the system what your application property. this can not be replaced by the Java code.
3、some resources files can be replaced by your Java code, but I think it's not a good idea to use the java code to replace the xml file. It's designed with MVC
I currently have an Android application that has an intent-filter to receive images from the Gallery. It is important that the images are received in the same order that the user selected them in. This seems to be the default behavior on most devices, however on some devices (so far I've seen this on Motorola's running Android 4.x) the order seems undefined. Does anyone know a way to declare in the intent that the images should be received in order? Or a way once the images are recieved to determine the selected order?
Here is relevant code from the manifest
<activity
android:label="#string/app_name"
android:name=".activities.ImportImagesActivity" >
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="image/*" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEND_MULTIPLE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="image/*" />
</intent-filter>
</activity>
And from ImportImagesActivity
private List<Uri> parseIncomingData() {
List<Uri> uriList = null;
Intent intent = this.getIntent();
if(intent != null) {
String action = intent.getAction();
//Single Image
if (action.equalsIgnoreCase("android.intent.action.SEND")) {
//removed for brevity
}
}
//Multiple Images
else if (action.equalsIgnoreCase("android.intent.action.SEND_MULTIPLE")) {
uriList = intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM);
}
}
//more code - at this point images have been recieved
return uriList;
}
EDIT
To give a little context, let me explain the general flow of the app.
The user opens the Gallery and selects images. They choose to 'Share' them with my app. My application receives a list of Uri's which are then displayed using an internal gallery backed by a custom Adapter class. The images display correctly based on the Uri list, the issue is the order of the List<Uri> is sometimes incorrect. It is important to my users that the images appear in the same order they select them in.
Clarification
When I use the term Gallery I am referring to the built in Android app Gallery.
When I use the term 'Share' I am referring to the the Share button within the Gallery app. This allows the user to select from a list of services such as Facebook, Email, and in this case my app.
For Example
imagine a Gallery with 3 images, displayed in an arbitrary order: A, B, and C. The user selects first C then A then B and chooses to share them with my app. On most phones my list will be correctly ordered {C, A, B}, on offending phones this order seems random.
I cannot use the creation timestamp because the creation time is generally irrelevant to the selection order. Adding custom meta data doesn't help either because I don't know the correct initial order.
My observation is that Android gallery displays images in accordance to their recency.
For the devices where you're unable to determine the order, you can import the images from the gallery and check their creation time. Here's a way to do that. Or you could use a metadata extractor app, many jars can be found.
Now, you could just arrange the images in the order of recency and you should be done.
[EDIT]
I have a question. You said they may be selected in any order, so are they "uploading" it onto a server by "sharing"?
If so, then one way is to check which image was uploaded or if you want the order of selection, you could do this. Edit the metadata of the images, there's bound to be a useless tag, select one and edit it on touch. So, if I select image A it changes to 1 and then I select image B it becomes 2. But if I unselect image A now then image B should become 1. So, you could use nodes here. This is the first in first out (FIFO) method. Upon un-selection, A is thrown out of the list and B replaces it.
Is this what you wanted?
EDIT
Sorry, I don't think you can do this without creating your own gallery. Why don't you just import the android gallery into a grid view in your app?
Yeah, I just faced the same problem right now. I am also using Fedor's lazy loading concept.I am not sure how far this will be helpful and whether this is the right approach. But still it solved the problem for me.
I had to do a little modification in the getView(),
#Override
public View getView(int position, View convertView, ViewGroup parent) {
System.gc();
ImageView view;
if(convertView == null) {
view = new ImageView(context);
view.setScaleType(ImageView.ScaleType.FIT_CENTER);
view.setLayoutParams(new GridView.LayoutParams(screenWidth/4, screenHeight/4));
view.setAdjustViewBounds(false);
view.setPadding(2, 2, 2, 2);
System.gc();
}else {
view = (ImageView) convertView;
}
if(view!=null)
{
imageLoader.DisplayImage(urlList.get(position), view);
notifyDataSetChanged(); //Calling this helped to solve the problem.
}
System.gc();
return view;
}