I'm trying to build an plugin-system which is importing Fragments from other apks as described here.
Eclipse keeps telling me:
12-01 15:17:18.609: W/dalvikvm(23425): Class resolved by unexpected DEX: Lde/anthropotec/activityapp/firstplugin/UI;(0x42901520):0x57d93000 ref [Lde/anthropotec/activityapp/api/PluginAPI;] Lde/anthropotec/activityapp/api/PluginAPI;(0x428eb2b8):0x527e1000
(Lde/anthropotec/activityapp/firstplugin/UI; had used a different Lde/anthropotec/activityapp/api/PluginAPI; during pre-verification)
Which isn't a suprise, as I'm importing my PluginAPI-libary in both, the Host and the Plugin. As far as I understand, Eclipse seems to be afraid, that these libaries aren't identical. Is there a way to tell Eclipse to not import the libary, if it's already there in the other apk? Or is there any other way to go around this. Please tell me if you need more information. Here's my source:
The Host:
package de.anthropotec.activityapp.host;
import java.io.File;
import dalvik.system.DexClassLoader;
import de.anthropotec.activityapp.api.PluginAPI;
import de.anthropotec.activtiyapp.host.R;
import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentTransaction;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.os.Bundle;
public class MainActivtiy extends Activity{
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
try {
Class<?> requiredClass = null;
final ApplicationInfo info = getPackageManager().getApplicationInfo("de.anthropotec.activityapp.firstplugin",0);
final String apkPath = info.sourceDir;
final File dexTemp = getDir("temp_folder", 0);
final String fullName = "de.anthropotec.activityapp.firstplugin.UI";
boolean isLoaded = true;
// Check if class loaded
try {
requiredClass = Class.forName(fullName);
} catch(ClassNotFoundException e) {
isLoaded = false;
}
if (!isLoaded) {
final DexClassLoader classLoader = new DexClassLoader(apkPath, dexTemp.getAbsolutePath(), null, getApplicationContext().getClassLoader());
requiredClass = classLoader.loadClass(fullName);
}
if (null != requiredClass) {
// Try to cast to required interface to ensure that it's can be cast
final PluginAPI holder = PluginAPI.class.cast(requiredClass.newInstance());
if (null != holder) {
final Fragment fragment = holder.getFragment();
if (null != fragment) {
final FragmentTransaction trans = getFragmentManager().beginTransaction();
trans.add(R.id.pluginPlace, fragment, "MyFragment").commit();
}
}
}
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
The PluginApi:
package de.anthropotec.activityapp.api;
import android.app.Fragment;
public interface PluginAPI {
public Fragment getFragment();
}
And the Plugin-Fragment itself:
package de.anthropotec.activityapp.firstplugin;
import de.anthropotec.activityapp.api.PluginAPI;
import android.app.Fragment;
import android.content.res.XmlResourceParser;
import android.os.Bundle;
import android.view.View;
import android.view.LayoutInflater;
import android.view.ViewGroup;
public class UI extends Fragment implements PluginAPI{
#Override
public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) {
// Note that loading of resources is not the same as usual, because it loaded actually from another apk
final XmlResourceParser parser = container.getContext().getPackageManager().getXml("de.anthropotec.testplugin", R.layout.ui, null);
return inflater.inflate(parser, container, false);
}
#Override
public Fragment getFragment() {
return this;
}
}
Each of the above as it's own Project (PluginAPI as libary). The question isn't quite new (e.g. here), but the already given answers advice to remove on of the imports, what doesn't seem to be a option in my case, as I need the API on both sides (Plugin and Host).
Ahww, sometimes it's so obvious. Just import the libary as extern libary in Properties->Java Build Path -> add external jar for the Plugin, and everything works just fine. Gnarf!
Related
I'm trying to implement the custom launchFragmentInHiltContainer() method in a Java project, and I've already gone through all the hoops of setting up kotlin and refactoring the reified parameters. However, when I try to compile the project, I am greeted by this puzzling error:
C:\Users\jedwa\AndroidStudioProjects\AppName\app\src\androidTest\java\com\example\appname\MainActivityTest.java:55: error: cannot access Hilt_FragmentPersonalDetails
HiltExtKt.launchFragmentInHiltContainer(FragmentPersonalDetails.class);
^
class file for com.example.appname.fragments.Hilt_FragmentPersonalDetails not found
FragmentPersonalDetails is a hilt-enabled fragment and works fine in production code. What is strange is that replacing FragmentPersonalDetails.class with a NonHiltFragment.class will allow the project to compile just fine.
What it will not do, however is stop a runtime error from occurring, which may be related. On replacing FragmentPersonalDetails with NonHiltFragment, I get:
java.lang.RuntimeException: Hilt test, MainActivityTest, is missing generated file: com.example.appname.MainActivityTest_TestComponentDataSupplier. Check that the test class is annotated with #HiltAndroidTest and that the processor is running over your test.
which I have seen before, except this time I most definitely do have #HiltAndroidTest on my test class. I've finally hit the point where the error is internal enough that I have no idea how to go about fixing it, though it seems like a dependency error of some sort. Files provided below for reference.
The hilt-enabled FragmentPersonalDetails
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;
import androidx.lifecycle.ViewModelStoreOwner;
import androidx.navigation.NavController;
import androidx.navigation.fragment.NavHostFragment;
import com.example.atease.R;
import com.example.atease.databinding.FragmentPersonalDetailsBinding;
import com.example.atease.viewmodels.LoginViewModel;
import dagger.hilt.android.AndroidEntryPoint;
#AndroidEntryPoint
public class FragmentPersonalDetails extends Fragment {
private FragmentPersonalDetailsBinding binding;
#Override
public View onCreateView(#NonNull LayoutInflater inflater,
ViewGroup container,
Bundle savedInstanceState) {
binding = FragmentPersonalDetailsBinding.inflate(inflater, container, false);
binding.setLifecycleOwner(this);
NavController navController = NavHostFragment.findNavController(this);
ViewModelStoreOwner store = navController.getViewModelStoreOwner(R.id.login_graph);
binding.setViewModel(new ViewModelProvider(store).get(LoginViewModel.class));
return binding.getRoot();
}
#Override
public void onViewCreated(#NonNull View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
binding.nextButton.setOnClickListener(view1 ->
NavHostFragment.findNavController(FragmentPersonalDetails.this)
.navigate(R.id.action_FragmentPersonalDetails_to_FragmentEmploymentDetails));
}
#Override
public void onDestroyView() {
super.onDestroyView();
binding = null;
}
}
The test class that won't compile
import androidx.test.espresso.IdlingRegistry;
import androidx.test.espresso.accessibility.AccessibilityChecks;
import com.example.atease.fragments.SecondFragment;
import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import javax.inject.Inject;
import dagger.hilt.android.testing.HiltAndroidRule;
import dagger.hilt.android.testing.HiltAndroidTest;
/**
* Instrumented test, which will execute on an Android device.
*
* #see Testing documentation
*/
#HiltAndroidTest
public class MainActivityTest {
#Inject DataBindingIdlingResource bindingIdlingResource;
#BeforeClass
public static void enableAccessibility() {
AccessibilityChecks.enable().setRunChecksFromRootView(true);
}
#Before
public void init() {
hiltRule.inject();
IdlingRegistry.getInstance().register(bindingIdlingResource);
}
#After
public void tearDown() {
IdlingRegistry.getInstance().unregister(bindingIdlingResource);
}
#Rule
public HiltAndroidRule hiltRule = new HiltAndroidRule(this);
//cycles through the nav-bar
#Test
public void testNavbar() {
HiltExtKt.launchFragmentInHiltContainer(SecondFragment.class);
}
}
My implementation of launchFragmentinHiltContainer. The only difference is that I took out the reified parameter types and added the extra class parameter, in order to be able to reference the methods from Java.
import android.content.ComponentName
import android.content.Intent
import android.os.Bundle
import androidx.annotation.StyleRes
import androidx.core.util.Preconditions
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentFactory
import androidx.test.core.app.ActivityScenario
import androidx.test.core.app.ApplicationProvider
import kotlinx.coroutines.ExperimentalCoroutinesApi
#JvmOverloads
#ExperimentalCoroutinesApi
inline fun <T : Fragment> launchFragmentInHiltContainer(
fragmentType: Class<T>,
fragmentArgs: Bundle? = null,
#StyleRes themeResId: Int = R.style.FragmentScenarioEmptyFragmentActivityTheme,
crossinline action: Fragment.() -> Unit = {}
) {
val startActivityIntent = Intent.makeMainActivity(
ComponentName(
ApplicationProvider.getApplicationContext(),
HiltTestActivity::class.java
)
).putExtra("androidx.fragment.app.testing.FragmentScenario.EmptyFragmentActivity.THEME_EXTRAS_BUNDLE_KEY",
themeResId)
ActivityScenario.launch<HiltTestActivity>(startActivityIntent).onActivity { activity ->
val fragment: Fragment = activity.supportFragmentManager.fragmentFactory.instantiate(
Preconditions.checkNotNull(fragmentType.classLoader),
fragmentType.name
)
fragment.arguments = fragmentArgs
activity.supportFragmentManager
.beginTransaction()
.add(android.R.id.content, fragment, "")
.commitNow()
fragment.action()
}
}
#JvmOverloads
#ExperimentalCoroutinesApi
inline fun <T : Fragment> launchFragmentInHiltContainer(
fragmentType: Class<T>,
fragmentArgs: Bundle? = null,
#StyleRes themeResId: Int = R.style.FragmentScenarioEmptyFragmentActivityTheme,
factory: FragmentFactory,
crossinline action: Fragment.() -> Unit = {}
) {
val startActivityIntent = Intent.makeMainActivity(
ComponentName(
ApplicationProvider.getApplicationContext(),
HiltTestActivity::class.java
)
).putExtra("androidx.fragment.app.testing.FragmentScenario.EmptyFragmentActivity.THEME_EXTRAS_BUNDLE_KEY",
themeResId)
ActivityScenario.launch<HiltTestActivity>(startActivityIntent).onActivity { activity ->
activity.supportFragmentManager.fragmentFactory = factory
val fragment: Fragment = activity.supportFragmentManager.fragmentFactory.instantiate(
Preconditions.checkNotNull(fragmentType.classLoader),
fragmentType.name
)
fragment.arguments = fragmentArgs
activity.supportFragmentManager
.beginTransaction()
.add(android.R.id.content, fragment, "")
.commit()
fragment.action()
}
}
Just rewrite the function in Java. I changed the signature to match the original FragmentScenario.launchInContainer.
import android.content.ComponentName;
import android.content.Intent;
import android.os.Bundle;
import androidx.annotation.StyleRes;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.test.core.app.ActivityScenario;
import androidx.test.core.app.ApplicationProvider;
import java.util.Objects;
public class HiltHelper {
public static void launchFragmentInHiltContainer(Class<? extends Fragment> fragmentClass, Bundle fragmentArgs, #StyleRes int themeResId) {
Intent intent = Intent.makeMainActivity(new ComponentName(ApplicationProvider.getApplicationContext(), HiltTestActivity.class))
.putExtra("androidx.fragment.app.testing.FragmentScenario.EmptyFragmentActivity.THEME_EXTRAS_BUNDLE_KEY", themeResId);
ActivityScenario.launch(intent)
.onActivity(activity -> {
Fragment fragment = ((AppCompatActivity) activity).getSupportFragmentManager().getFragmentFactory()
.instantiate(Objects.requireNonNull(fragmentClass.getClassLoader()), fragmentClass.getName());
fragment.setArguments(fragmentArgs);
((AppCompatActivity) activity).getSupportFragmentManager()
.beginTransaction()
.add(android.R.id.content, fragment, "")
.commitNow();
});
}
}
It doesn't show the text from internet, just shows 000.
I wanted to get a text from internet and show on widget.
But I haven't got it to work successfully.
This is the code (Java class):
import android.appwidget.AppWidgetProvider;
import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import android.widget.RemoteViews;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
public class simple_widget extends AppWidgetProvider {
public void onCreateView(Context context, LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
try {
// Create a URL for the desired page
URL url = new URL("mysite.com/thefile.txt");
// Read all the text returned by the server
BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream()));
String str;
while ((str = in.readLine()) != null) {
RemoteViews remoteViews = new RemoteViews(context.getPackageName(),
R.layout.activity_simple_widget);
remoteViews.setTextViewText(R.id.textView, str);
}
in.close();
} catch (MalformedURLException e) {
} catch (IOException e) {
}
}
}
What's wrong with the code?
You need to modify it using RemoteViews. You can't actually modify a view on the appwidget directly
Here are a few examples
I take it you want to use setText() in appWidgetProvider class. But this class does not allow findViewById(). You need to use a function of RemoteView Class for this purpose.
CharSequence Method | Android Developers
in your case:
remoteViews.setCharSequence(R.id.textView,"setText",str);
it works for EditText,TextView,TextClock.
You can replace String MethodName with the name of method like getText,setText,setTimeZone etc.
For Buttons RemoteViews offer the following function
setOnClickResponse | Android Developers
this is the equivalent of
View.setOnClickListener(android.view.View.OnClickListener)
Similarly a lot of other methods are available now such as setFloat(), setLong() which work same as setCharSequence().
you can choose between them based on the datatype of parameters you want to pass.
here is the link to understand and view the list of all RemoteView functions
RemoteViews | Android Developers
Hope this helps
In Android, I am trying to override the toString() of the ParseUser for use in my listview, using
import android.os.Bundle;
import android.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import com.parse.FindCallback;
import com.parse.ParseException;
import com.parse.ParseQuery;
import com.parse.ParseUser;
import java.util.List;
/**
* A simple {#link Fragment} subclass.
*/
public class ExampleFragment extends Fragment {
public ExampleFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final View rootView = inflater.inflate(R.layout.fragment_example, container, false);
final ListView listView = (ListView) rootView.findViewById(R.id.exampleListView);
ParseQuery query = User.getQuery();
query.findInBackground(new FindCallback<User>() {
public void done(List<User> objects, ParseException e) {
if (e == null) {
// The query was successful.
listView.setAdapter(new ArrayAdapter<User>(rootView.getContext(), android.R.layout.simple_list_item_1, objects));
for (User user : objects) {
Log.i("AppInfo", "Added " + user.toString());
}
} else {
// Something went wrong.
}
}
});
return rootView;
}
public class User extends ParseUser {
#Override
public String toString() {
Log.i("AppInfo", "Username: " + getUsername());
return getUsername();
}
}
}
Seems simple enough. I had this nested in my fragment class and it crashed with this
java.lang.ClassCastException: com.parse.ParseUser cannot be cast to com.mycompany.myproject.ExampleFragment$User
but when I move it into its own subclass (where it gets its own entry in the explorer view in android studio), it works perfectly.
Is there a reason it does not work nested in my fragment class? Seems a bit unnecessary to create its own subclass just to override one function.
UPDATE: If I remove the for loop part it does not error out, but it still does not call my overridden toString() as the listview returns com.parse.ParseUser#etcetcetc.
make sure you have do these 2 things
1.register class before Parse.initialize
ParseObject.registerSubclass(User.class);
2.use annotation to specified the class mapping to waht Class
#ParseClassName("_User")
public class User extends ParseUser {
...
}
here is the reference.
https://parse.com/docs/android/guide#objects-subclassing-parseobject
I'm creating an app that I want to stream my foscam live feed in. I'm pretty new to coding and some of this code is over my head. I found some help getting this far but now am hitting a snag. The app runs but only displays a black screen. I believe i have the manifest and XML code all correct. The problem lies in my code. I hope someone can help me out
package com.rednak.camerastream;
import android.app.Activity;
import android.content.Context;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Bundle;
import android.util.Base64;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.Window;
import android.view.WindowManager;
import java.util.HashMap;
import java.util.Map;
public class MainActivity extends Activity
implements MediaPlayer.OnPreparedListener,
SurfaceHolder.Callback {
final static String USERNAME = "guest";
final static String PASSWORD = "Guest";
final static String RTSP_URL = "rtsp://http://rednak71.ddns.net:8090/live1.sdp";
private MediaPlayer _mediaPlayer;
private SurfaceHolder _surfaceHolder;
#
Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Set up a full-screen black window.
requestWindowFeature(Window.FEATURE_NO_TITLE);
Window window = getWindow();
window.setFlags(
WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
window.setBackgroundDrawableResource(android.R.color.black);
setContentView(R.layout.activity_main);
// Configure the view that renders live video.
SurfaceView surfaceView =
(SurfaceView) findViewById(R.id.surfaceView);
_surfaceHolder = surfaceView.getHolder();
_surfaceHolder.addCallback(this);
_surfaceHolder.setFixedSize(320, 240);
}
// More to come…
/*
SurfaceHolder.Callback
*/
#
Override
public void surfaceChanged(
SurfaceHolder sh, int f, int w, int h) {}
#
Override
public void surfaceCreated(SurfaceHolder sh) {
_mediaPlayer = new MediaPlayer();
_mediaPlayer.setDisplay(_surfaceHolder);
Context context = getApplicationContext();
Map headers = getRtspHeaders();
Uri source = Uri.parse(RTSP_URL);
try {
// Specify the IP camera’s URL and auth headers.
_mediaPlayer.setDataSource(context, source, headers);
// Begin the process of setting up a video stream.
_mediaPlayer.setOnPreparedListener(this);
_mediaPlayer.prepareAsync();
} catch (Exception e) {}
}
#
Override
public void surfaceDestroyed(SurfaceHolder sh) {
_mediaPlayer.release();
}
private Map getRtspHeaders() {
Map headers = new HashMap();
String basicAuthValue = getBasicAuthValue(USERNAME, PASSWORD);
headers.put("Authorization", basicAuthValue);
return headers;
}
private String getBasicAuthValue(String usr, String pwd) {
String credentials = usr + ":" + pwd;
int flags = Base64.URL_SAFE | Base64.NO_WRAP;
byte[] bytes = credentials.getBytes();
return "Basic" + Base64.encodeToString(bytes, flags);
}
/*
MediaPlayer.OnPreparedListener
*/
#
Override
public void onPrepared(MediaPlayer mp) {
_mediaPlayer.start();
}
}
Make sure that Android's MediaPlayer can actually open and decode your stream. Right now, if the MediaPlayer cannot handle your stream, you are catching any exception and silently ignoring it:
try {
// Specify the IP camera’s URL and auth headers.
_mediaPlayer.setDataSource(context, source, headers);
// Begin the process of setting up a video stream.
_mediaPlayer.setOnPreparedListener(this);
_mediaPlayer.prepareAsync();
} catch (Exception e) {}
At the very least you should log the error:
} catch (Exception e) {
Log.e("MyApp", "Could not open data source", e);
}
Although the MediaPlayer service will most likely pepper the log with its own errors. So what you should do is review the logcat for any messages from the "VideoDecoder" or similar.
To see the logcat in Android Studio, open the "Android Monitor" tab which is on the bottom by default. If you want to see the unfiltered logcat make sure that in the top-right corner of the Android Monitor view it says "No Filters" instead of "Show only selected application".
I have some new code that links to the Foscam videostream but only grabs the frame when it starts then does not stream. Im closer but still need help. Am i on the right track here?
package com.rednak.camstream;
import android.net.Uri;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.VideoView;
public class MainCamActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_cam);
VideoView vidView = (VideoView)findViewById(R.id.CamVideoView);
String vidAddress = "http://rednak71.ddns.net:8090/CGIProxy.fcgi? cmd=snapPicture2&usr=guest&pwd=guest&t=";
Uri vidUri = Uri.parse(vidAddress);
vidView.setVideoURI(vidUri);
vidView.start();
}
}
I've defined a remote service in an Android Library project using AIDL. The service is supposed to simply increment an int. I try to bind to it from another project, an application using the library. The application's call to bindService(...) always returns false. What am I doing wrong?
The main activity of the application project:
MainActivity.java
package com.example.serviceusera;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import com.example.service.IncService;
import com.example.service.IncServiceConnection;
public class MainActivity extends Activity {
private static final String TAG = MainActivity.class.getSimpleName();
private IncServiceConnection mConnection;
private int mCount = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
try {
mConnection = bindService();
} catch (RemoteException e) {
Log.e(TAG, "Failed to bind service", e);
}
}
#Override
protected void onDestroy() {
super.onDestroy();
unbindService(mConnection);
}
private IncServiceConnection bindService() throws RemoteException {
IncServiceConnection connection = new IncServiceConnection();
Intent service = new Intent(IncService.class.getName());
boolean bound = bindService(service, connection, Context.BIND_AUTO_CREATE);
Log.d(TAG, "bindService() = " + bound);
if (bound) {
return connection;
} else {
throw new RemoteException("Failed to bind service");
}
}
private void init() {
// Show the current value of the counter
final EditText text = (EditText) findViewById(R.id.editText1);
text.setText(Integer.toString(mCount));
// Set button to increment counter
Button button = (Button) findViewById(R.id.button1);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
try {
mCount = mConnection.inc(mCount);
text.setText(Integer.toString(mCount));
} catch (RemoteException e) {
Log.e(TAG, "Failed to use service", e);
}
}
});
}
}
The library project:
IIncService.aidl
package com.example.service;
interface IIncService {
int inc(in int i);
}
IncService.java
package com.example.service;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
public class IncService extends Service {
private final IIncService.Stub mBinder = new IIncService.Stub() {
#Override
public int inc(int i) throws RemoteException {
return i + 1;
}
};
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
}
IncServiceConnection.java
package com.example.service;
import android.content.ComponentName;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.RemoteException;
public class IncServiceConnection implements ServiceConnection {
private IIncService mService;
public int inc(int i) throws RemoteException {
return mService.inc(i);
}
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
mService = IIncService.Stub.asInterface(service);
}
#Override
public void onServiceDisconnected(ComponentName name) {
}
}
I've added the service to the library's manifest:
AndroidManifest.xml
...
<application
...
<service
android:name="com.example.service.IncService"
android:process=":remote" >
</service>
</application>
...
and enabled mainfest merging in the application:
project.properties
...
manifestmerger.enabled=true
I've tried Your code using IntelliJ Idea 13 and have found the issue.
Firstly, I ensured that:
Library project is exported;
Application project has Enable manifest merging on under Android Compiler properties;
Using that configuration it didn't work and I've observed Unable to start service Intent.
The issue here is in incorrect Intent creation. Seems that class name You obtain by IncService.class.getName() doesn't specify the component completely (if logs checked it looks like so, because intent contains only class name, but package name is missed). So, to specify component properly, I've used another way:
final Intent service = new Intent(this, IncService.class);
And it worked fine.
Instead of binding Ibinder, try using binding with Handler. I have recently done an application the way you did and I could not figure out the fault. But working with Messager made things easier.
Instead of return binder object. It returns message obj. Here is the reference.
Source: Android Remote Bound Services