Inflated float action buttons from android.support.design.widget.FloatingActionButton
(Project Overview section).
I want to make a fly button on all other apps and system icons. Once you press it, a menu will pop up from which you can select multiple options. After pressing and moving the button, you can move it anywhere on the screen.
So far, I have an on-screen fly button (actually a flying bmp file) in one project and a float button with a pop-up menu in the second.
What I’m going to do now is replace the bmp file with a real float button with a menu.
The way I tried to do this :
(The most important thing starts here) 🙂
I added the fly button to the windowManager via the addView method. The flyingbutton is a View object. That’s where I came to the harvester.
I’m trying to do how to find a View by id in a service class, and I’m doing this by inflating the android.support.design.widget.FloatingActionButton class
But now I find that the inflate method does not work for the class.
I’ve seen very few posts on Stack Overflow, but none of them have helped me.
Any ideas?
Maybe you’ll find that the background isn’t transparent so far, but that’s not the current problem. 🙂
logcat says….
FATAL EXCEPTION: main
Process: com.example.komp.floatingbuttonpowtorka, PID: 32452
java.lang.RuntimeException: Unable to create service com.example.komp.floatingbuttonpowtorka.FlyingButton: android.view.InflateException: Binary XML file line #8: Error inflating class <unknown>
at android.app.ActivityThread.handleCreateService(ActivityThread.java:2780)
at android.app.ActivityThread.access$1800(ActivityThread.java:151)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1424)
at android.os.Handler.dispatchMessage(Handler.java:110)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:5333)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:828)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:644)
at dalvik.system.NativeStart.main(Native Method)
Caused by: android.view.InflateException: Binary XML file line #8: Error inflating class <unknown>
at android.view.LayoutInflater.createView(LayoutInflater.java:620)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:696)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:755)
at android.view.LayoutInflater.inflate(LayoutInflater.java:492)
at android.view.LayoutInflater.inflate(LayoutInflater.java:397)
at android.view.LayoutInflater.inflate(LayoutInflater.java:353)
at com.example.komp.floatingbuttonpowtorka.FlyingButton.onCreate(FlyingButton.java:63)
at android.app.ActivityThread.handleCreateService(ActivityThread.java:2770)
at android.app.ActivityThread.access$1800(ActivityThread.java:151)Â
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1424)Â
at android.os.Handler.dispatchMessage(Handler.java:110)Â
at android.os.Looper.loop(Looper.java:193)Â
at android.app.ActivityThread.main(ActivityThread.java:5333)Â
at java.lang.reflect.Method.invokeNative(Native Method)Â
at java.lang.reflect.Method.invoke(Method.java:515)Â
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:828)Â
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:644)Â
at dalvik.system.NativeStart.main(Native Method)Â
Caused by: java.lang.reflect.InvocationTargetException
at java.lang.reflect.Constructor.constructNative(Native Method)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at android.view.LayoutInflater.createView(LayoutInflater.java:594)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:696)Â
at android.view.LayoutInflater.rInflate(LayoutInflater.java:755)Â
at android.view.LayoutInflater.inflate(LayoutInflater.java:492)Â
at android.view.LayoutInflater.inflate(LayoutInflater.java:397)Â
at android.view.LayoutInflater.inflate(LayoutInflater.java:353)Â
at com.example.komp.floatingbuttonpowtorka.FlyingButton.onCreate(FlyingButton.java:63)Â
at android.app.ActivityThread.handleCreateService(ActivityThread.java:2770)Â
at android.app.ActivityThread.access$1800(ActivityThread.java:151)Â
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1424)Â
at android.os.Handler.dispatchMessage(Handler.java:110)Â
at android.os.Looper.loop(Looper.java:193)Â
at android.app.ActivityThread.main(ActivityThread.java:5333)Â
at java.lang.reflect.Method.invokeNative(Native Method)Â
at java.lang.reflect.Method.invoke(Method.java:515)Â
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:828)Â
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:644)Â
at dalvik.system.NativeStart.main(Native Method)Â
Caused by: java.lang.IllegalArgumentException: You need to use a Theme.AppCompat theme (or descendant) with the design library.
at android.support.design.widget.ThemeUtils.checkAppCompatTheme(ThemeUtils.java:34)
at android.support.design.widget.FloatingActionButton.<init>(FloatingActionButton.java:110)
at android.support.design.widget.FloatingActionButton.<init>(FloatingActionButton.java:104)
at java.lang.reflect.Constructor.constructNative(Native Method)Â
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)Â
at android.view.LayoutInflater.createView(LayoutInflater.java:594)Â
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:696)Â
at android.view.LayoutInflater.rInflate(LayoutInflater.java:755)Â
at android.view.LayoutInflater.inflate(LayoutInflater.java:492)Â
at android.view.LayoutInflater.inflate(LayoutInflater.java:397)Â
at android.view.LayoutInflater.inflate(LayoutInflater.java:353)Â
at com.example.komp.floatingbuttonpowtorka.FlyingButton.onCreate(FlyingButton.java:63)Â
at android.app.ActivityThread.handleCreateService(ActivityThread.java:2770)Â
at android.app.ActivityThread.access$1800(ActivityThread.java:151)Â
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1424)Â
at android.os.Handler.dispatchMessage(Handler.java:110)Â
at android.os.Looper.loop(Looper.java:193)Â
at android.app.ActivityThread.main(ActivityThread.java:5333)Â
at java.lang.reflect.Method.invokeNative(Native Method)Â
at java.lang.reflect.Method.invoke(Method.java:515)Â
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:828)Â
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:644)Â
at dalvik.system.NativeStart.main(Native Method)
MainActivity.java
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
startService(new Intent(MainActivity.this, FlyingButton.class));
finish();
}
@Override
protected void onResume() {
Bundle bundle = getIntent().getExtras();
if(bundle != null && bundle.getString("LAUNCH").equals("YES")) {
startService(new Intent(MainActivity.this, FlyingButton.class));
}
super.onResume();
}
}
FlyingButton.java
public class FlyingButton extends Service {
private WindowManager windowManager;
private ImageView chatHead;
@Override
public IBinder onBind(Intent intent) {
TODO Auto-generated method stub
return null;
}
@Override
public void onCreate() {
super.onCreate();
windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
chatHead = new ImageView(this);
chatHead.setImageResource(R.drawable.floating);
LayoutInflater inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
View layout = inflater.inflate(R.layout.activity_main, null);
FloatingActionButton fab = (FloatingActionButton) layout.findViewById(R.id.fab);
final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_PHONE,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSLUCENT);
params.gravity = Gravity.TOP | Gravity.LEFT;
params.x = 0;
params.y = 100;
windowManager.addView(fab, params);
try {
chatHead.setOnTouchListener(new View.OnTouchListener() {
private WindowManager.LayoutParams paramsF = params;
private int initialX;
private int initialY;
private float initialTouchX;
private float initialTouchY;
@Override public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
Get current time in nano seconds.
initialX = paramsF.x;
initialY = paramsF.y;
initialTouchX = event.getRawX();
initialTouchY = event.getRawY();
break;
case MotionEvent.ACTION_UP:
break;
case MotionEvent.ACTION_MOVE:
paramsF.x = initialX + (int) (event.getRawX() - initialTouchX);
paramsF.y = initialY + (int) (event.getRawY() - initialTouchY);
windowManager.updateViewLayout(chatHead, paramsF);
break;
}
return false;
}
});
} catch (Exception e) {
TODO: handle exception
}
}
@Override
public void onDestroy() {
super.onDestroy();
if (chatHead != null) windowManager.removeView(chatHead);
}
}
activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context=". MainActivity">
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="16dp"
android:src="@drawable/filter"
app:backgroundTint="@color/colorAccent"
xmlns:android="http://schemas.android.com/apk/res/android" />
</RelativeLayout>
styles.xml
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
androidmanifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.komp.floatingbuttonpowtorka"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="10"
android:targetSdkVersion="18" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/Theme.AppCompat" >
<activity
android:name=". MainActivity"
android:label="@string/app_name"
android:screenOrientation="portrait"
android:theme="@style/Theme.AppCompat">
<application android:name=". ApplicationContextProvider"
android:label="@string/app_name"/>
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name="com.example.komp.floatingbuttonpowtorka.FlyingButton"
android:exported="true" />
</application>
</manifest>
Gradients
Application plugin: ‘com.android.application’
Android {
Compile SDK version 23
buildToolsVersion “23.0.3”
defaultConfig {
applicationId "com.example.komp.floatingbuttonpowtorka"
minSdkVersion 15
targetSdkVersion 23
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.1.1'
compile 'com.android.support:design:23.1.1'
}
Solution
It is as if the theme is set in the activity, not in the service.
To specify one programmatically, add it to the onCreate
method of the service.
setTheme(R.style.AppTheme);
It will fix your specific error, but the app will not work as is.
1.
I had to change
windowManager.addView(fab, params);
to windowManager.addView(layout, params);
2.
The application will not run with targetSdkVersion
set to 23 or higher.
(Set build.gradle
in your targetSdkVersion 22
file) This answer will maybe help
Some notes:
1.
You are not using the style declared in styles.xml
In the AndroidManifest .xml
, you need to change android:theme=”@style/Theme.AppCompat" to android:theme="@style/AppTheme
"
Set it only to <Application>
apply it to all activities.
2.
In your AndroidManifest .xml
, line
<uses-sdk android:minSdkVersion="10" android:targetSdkVersion="18" />
It can be removed because this information is already specified in the file in build.gradle.