Callback when saving a file - android

I'm a newbie and I want to use CameraView library, the "toFile" function has two parameters. What does "callback" mean here?
camera.addCameraListener(new CameraListener() {
#Override
public void onPictureTaken(PictureResult result) {
result.toFile(file, **callback**);
}
});
camera.takePicture();

It will notify you when the file has been written.
Extract from the source code:
/**
* Receives callbacks about a file saving operation.
*/
public interface FileCallback {
/**
* Notifies that the data was succesfully written to file.
* This is run on the UI thread.
* Returns a null object if an exception was encountered, for example
* if you don't have permissions to write to file.
*
* #param file the written file, or null
*/
#UiThread
void onFileReady(#Nullable File file);
}

Related

By what i can replace ViewTreeObserver.OnComputeInternalInsetsListener that is declared as hidden?

I try to import in my library some android internal source code. however i have some trouble to import this part of code :
private final ViewTreeObserver.OnComputeInternalInsetsListener mInsetsComputer =
new ViewTreeObserver.OnComputeInternalInsetsListener() {
public void onComputeInternalInsets(
ViewTreeObserver.InternalInsetsInfo info) {
info.contentInsets.setEmpty();
info.visibleInsets.setEmpty();
info.touchableRegion.set(mTouchableRegion);
info.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo
.TOUCHABLE_INSETS_REGION);
}
};
it's because in ViewTreeObserver.java OnComputeInternalInsetsListener is declared as hidden
/**
* Interface definition for a callback to be invoked when layout has
* completed and the client can compute its interior insets.
*
* We are not yet ready to commit to this API and support it, so
* #hide
*/
public interface OnComputeInternalInsetsListener {
/**
* Callback method to be invoked when layout has completed and the
* client can compute its interior insets.
*
* #param inoutInfo Should be filled in by the implementation with
* the information about the insets of the window. This is called
* with whatever values the previous OnComputeInternalInsetsListener
* returned, if there are multiple such listeners in the window.
*/
public void onComputeInternalInsets(InternalInsetsInfo inoutInfo);
}
later i use it like this
/**
* Make the touchable area of this popup be the area specified by mTouchableRegion.
* This should be called after the popup window has been dismissed (dismiss/hide)
* and is probably being re-shown with a new content root view.
*/
private void setTouchableSurfaceInsetsComputer() {
ViewTreeObserver viewTreeObserver = mPopupWindow.getContentView()
.getRootView()
.getViewTreeObserver();
viewTreeObserver.removeOnComputeInternalInsetsListener(mInsetsComputer);
viewTreeObserver.addOnComputeInternalInsetsListener(mInsetsComputer);
}
so by what i can replace ViewTreeObserver.OnComputeInternalInsetsListener, removeOnComputeInternalInsetsListener and addOnComputeInternalInsetsListener ? i don't even know the purpose of these functions ...

Consecutive Android Junit tests do not reflect the real data in the underlying database

Additional Information:
To clarify, the app under test uses a ContentProvider to access the database.
Edit:
If anyone is willing and able to help me debug this. The full project is available here. In the issue107-contentprovider branch, BaseballCardListAddCardsTest.
Question:
When I run two of my Android JUnit tests separately, they pass just fine. However, when I run them together, the first one passes and the second one fails. The problem appears to be that the first test run adds a row to the underlying database. tearDown() correctly deletes the database, but the second test still starts with the dirty data displayed in the ListView although the database does not contain the extra row. (I confirmed this using adb shell.) Does anyone have any ideas how I can fix this problem?
The Activity class being tested can be found here.
Here is my test code:
/**
* Tests for the {#link BaseballCardList} activity when the database contains
* data.
*/
public class BaseballCardListWithDataTest extends
ActivityInstrumentationTestCase2<BaseballCardList> {
/**
* Create instrumented test cases for {#link BaseballCardList}.
*/
public BaseballCardListWithDataTest() {
super(BaseballCardList.class);
}
/**
* Set up test fixture. This consists of an instance of the
* {#link BaseballCardList} activity, its {#link ListView}, and a populated
* database.
*
* #throws Exception
* If an error occurs while chaining to the super class.
*/
#Override
public void setUp() throws Exception {
super.setUp();
this.inst = this.getInstrumentation();
// Create the database and populate table with test data
InputStream cardInputStream = this.inst.getContext().getAssets()
.open(BBCTTestUtil.CARD_DATA);
BaseballCardCsvFileReader cardInput = new BaseballCardCsvFileReader(
cardInputStream, true);
this.allCards = cardInput.getAllBaseballCards();
cardInput.close();
this.dbUtil = new DatabaseUtil(this.inst.getTargetContext());
this.dbUtil.populateTable(this.allCards);
// Start Activity
this.activity = this.getActivity();
this.listView = (ListView) this.activity
.findViewById(android.R.id.list);
this.newCard = new BaseballCard("Code Guru Apps", 1993, 1, 50000, 1,
"Code Guru", "Code Guru Devs", "Catcher");
}
/**
* Tear down the test fixture by calling {#link Activity#finish()} and
* deleting the database.
*
* #throws Exception
* If an error occurs while chaining to the super class.
*/
#Override
public void tearDown() throws Exception {
this.dbUtil.deleteDatabase();
super.tearDown();
}
/**
* Check preconditions which must hold to guarantee the validity of all
* other tests. Assert that the {#link Activity} to test and its
* {#link ListView} are not <code>null</code>, that the {#link ListView}
* contains the expected data, and that the database was created with the
* correct table and populated with the correct data.
*/
public void testPreConditions() {
Assert.assertNotNull(this.activity);
BBCTTestUtil.assertDatabaseCreated(this.inst.getTargetContext());
Assert.assertTrue(this.dbUtil.containsAllBaseballCards(this.allCards));
Assert.assertNotNull(this.listView);
BBCTTestUtil.assertListViewContainsItems(this.inst, this.allCards,
this.listView);
}
/**
* Test that the {#link ListView} is updated when the user adds a new card
* which matches the current filter.
*
* #throws Throwable
* If an error occurs while the portion of the test on the UI
* thread runs.
*/
public void testAddCardMatchingCurrentFilter() throws Throwable {
this.testYearFilter();
Activity cardDetails = BBCTTestUtil.testMenuItem(this.inst,
this.activity, R.id.add_menu, BaseballCardDetails.class);
BBCTTestUtil.addCard(this, cardDetails, this.newCard);
BBCTTestUtil.clickCardDetailsDone(this, cardDetails);
this.expectedCards.add(this.newCard);
BBCTTestUtil.assertListViewContainsItems(this.inst, this.expectedCards,
this.listView);
}
/**
* Test that the {#link ListView} is updated when the user adds a new card
* after an active filter was cleared.
*
* #throws Throwable
* If an error occurs while the portion of the test on the UI
* thread runs.
*/
public void testAddCardAfterClearFilter() throws Throwable {
this.testClearFilter();
Activity cardDetails = BBCTTestUtil.testMenuItem(this.inst,
this.activity, R.id.add_menu, BaseballCardDetails.class);
BBCTTestUtil.addCard(this, cardDetails, this.newCard);
BBCTTestUtil.clickCardDetailsDone(this, cardDetails);
this.allCards.add(this.newCard);
BBCTTestUtil.assertListViewContainsItems(this.inst, this.allCards,
this.listView);
}
private List<BaseballCard> allCards;
private List<BaseballCard> expectedCards;
private Instrumentation inst = null;
private Activity activity = null;
private DatabaseUtil dbUtil = null;
private ListView listView = null;
private BaseballCard newCard = null;
private static final int TIME_OUT = 5 * 1000; // 5 seconds
private static final String TAG = BaseballCardListWithDataTest.class
.getName();
}
It appears that a ContentProvider's lifecycle is tied to that of an Application not of the Activity that acesses it. Also, from what I can tell, ActivityInstrumentationTestCase2 creates a single Application for all the tests; only the Activity is destroyed and restarted for each test. This means that the each test will share the same ContentProvider. This means that the database file is opened with the first access by the ContentProvider and closed only after all test methods in the ActivityInstrumentationTestCase2 have finished. Since the database file remains open between test cases, the data can be accessed even after the file is deleted from the underlying file system. My solution was to delete the rows of the database individually rather than deleting the entire database.

How to fill-in EditText field in Android tests

Does anybody have any experience with creating tests for an android project? I started setting up my testing project and noticed that there is not much documentation at all. I am trying to setup a test to test a username and password field. I have it working without filling in the inputs username or password. But now when I try to set those up I keep getting java.lang.NullPointerException but I don't see why or how. Here is a sample of code that I am working on.
public class GasTrackerTab1Test extends ActivityInstrumentationTestCase2<GasTrackerTab1> {
private Activity mActivity; // MyActivity is the class name of the app under test
private EditText username;
private EditText password;
private Button loginButton;
#SuppressWarnings("deprecation")
public GasTrackerTab1Test() {
super("com.wallproductions.gas.tracker", GasTrackerTab1.class);
}
#Override
protected void setUp() throws Exception {
/*
* Call the super constructor (required by JUnit)
*/
super.setUp();
/*
* prepare to send key events to the app under test by turning off touch mode.
* Must be done before the first call to getActivity()
*/
setActivityInitialTouchMode(false);
/*
* Start the app under test by starting its main activity. The test runner already knows
* which activity this is from the call to the super constructor, as mentioned
* previously. The tests can now use instrumentation to directly access the main
* activity through mActivity.
*/
mActivity = getActivity();
username = (EditText)mActivity.findViewById(com.wallproductions.gas.tracker.R.id.login_user_name);
password = (EditText)mActivity.findViewById(com.wallproductions.gas.tracker.R.id.login_password);
loginButton = (Button)mActivity.findViewById(com.wallproductions.gas.tracker.R.id.mainloginbtn);
} // end of setUp() method definition
/*
* Tests the initial values of key objects in the app under test, to ensure the initial
* conditions make sense. If one of these is not initialized correctly, then subsequent
* tests are suspect and should be ignored.
*/
public void testPreconditions() {
assertNotNull(username);
assertNotNull(password);
}
public void testInvalidUserNamePassword() {
mActivity.runOnUiThread(
new Runnable() {
public void run() {
username.setFocus();
username.setText("tester");
password.setFocus();
password.setText("test1234");
loginButton.performClick();
}
}
);
}
}
The question is there any good documentation to look at to figure this out? Also how do you fill in a EditText box with some text and then verify through an alert that the correct response is given.
This worked for me:
onView(withId(R.id.text_edit_id)).perform(typeText(someString));
I believe I have found my answer at
http://www.java2s.com/Open-Source/Android/android-core/platform-tools-tradefederation/com/android/tradefed/uitestapp/EditBoxActivityTest.java.htm
Basically I needed to add in #UiThreadTest above my method and then using setText works. Not using the Runable class.
public class GasTrackerTab1Test extends ActivityInstrumentationTestCase2<GasTrackerTab1> {
private Activity mActivity; // MyActivity is the class name of the app under test
private EditText username;
private EditText password;
private Button loginButton;
#SuppressWarnings("deprecation")
public GasTrackerTab1Test() {
super("com.wallproductions.gas.tracker", GasTrackerTab1.class);
}
#Override
protected void setUp() throws Exception {
/*
* Call the super constructor (required by JUnit)
*/
super.setUp();
/*
* prepare to send key events to the app under test by turning off touch mode.
* Must be done before the first call to getActivity()
*/
setActivityInitialTouchMode(false);
/*
* Start the app under test by starting its main activity. The test runner already knows
* which activity this is from the call to the super constructor, as mentioned
* previously. The tests can now use instrumentation to directly access the main
* activity through mActivity.
*/
mActivity = getActivity();
username = (EditText)mActivity.findViewById(com.wallproductions.gas.tracker.R.id.login_user_name);
password = (EditText)mActivity.findViewById(com.wallproductions.gas.tracker.R.id.login_password);
loginButton = (Button)mActivity.findViewById(com.wallproductions.gas.tracker.R.id.mainloginbtn);
} // end of setUp() method definition
/*
* Tests the initial values of key objects in the app under test, to ensure the initial
* conditions make sense. If one of these is not initialized correctly, then subsequent
* tests are suspect and should be ignored.
*/
public void testPreconditions() {
assertNotNull(username);
assertNotNull(password);
}
/**
* Test that the edit box on {#link EditBoxActivity} can focused.
*/
#UiThreadTest
public void testUsernameTextFocus() {
assertNotNull(username);
assertTrue(username.requestFocus());
assertTrue(username.hasFocus());
}
#UiThreadTest
public void testPasswordTextFocus() {
assertNotNull(password);
assertTrue(password.requestFocus());
assertTrue(password.hasFocus());
}
#UiThreadTest
public void testInvalidUserNamePassword() {
username.requestFocus();
username.setText("testing");
password.requestFocus();
password.setText("whatever");
loginButton.callOnClick();
}
}

Returning an AIDL interface implementation by reference across processes

I have a little Android project going on which involves some IPC where client Activities bind to my service.
I'm using AIDL for IPC and RPC which works pretty good, but I'm having trouble returning a service-side instantiated AIDL interface implementation to the clients:
When the client is running in the same process as the service -- meaning running the service locally -- everything works just fine.
But when client and service are seperated in different processes the method startLogSession, which is defined in ILogDroidBinder.aidl always returns null.
The other method implemented in this interface -- getSessionIds -- which returns a List containing ints, always works (locally and cross-process).
I'm taking a wild guess and suppose my ILogDroidSession implementation should also implement Parcelable, but that wouldn't work, because I can't parcel an object containg a reference to an SQLiteDatabase (or can I?).
Here is the relevant code.
I'd really be glad if someone could help me out here. Maybe I'm just missing a point somewhere, since this is my first Android project and I'm not quite involved yet.
ILogDroidSession.aidl (An implementation of this is what I want to return to the client):
package net.sourceforge.projects.logdroid;
interface ILogDroidSession {
/**
* Logs the given text to the error message channel of the current logging
* session.
* #param text Text to log.
*/
void logError(in String text);
}
ILogDroidBinder.aidl (The IBinder interface passed to the client's onServiceConnected):
package net.sourceforge.projects.logdroid;
import net.sourceforge.projects.logdroid.ILogDroidSession;
interface ILogDroidBinder {
/**
* Starts a new LogDroid session which handles all logging events.
* #param sessionName The name of the session.
* #return An instance of ILogDroidSession.
*/
ILogDroidSession startLogSession(in String sessionName);
/**
* Gets a list with all available LogSession ids.
*/
List getSessionIds();
}
LogDroidService.java (Relevant code from my service):
public class LogDroidService extends Service {
/**
* The binder interface needed for Activities to bind to the
* {#code LogDroidService}.
*/
private final ILogDroidBinder.Stub binder = new ILogDroidBinder.Stub() {
/**
* Starts a new LogDroidSession.
*/
public ILogDroidSession startLogSession(String sessionName) {
return LogDroidService.this.createSession(sessionName);
}
/**
* Gets all available session ids.
*/
public List<Integer> getSessionIds() {
return LogDroidService.this.getSessionIds();
}
};
/**
* The database connection to be used for storing and retrieving log entries.
*/
private LogDroidDb database;
#Override
public void onCreate() {
super.onCreate();
database = new LogDroidDb(getApplicationContext());
try {
database.open(); // opens as writable database
} catch ( SQLException ignorefornow ) {
}
}
#Override
public IBinder onBind(Intent ignore) {
return binder;
}
/**
* Creates a new LogDroidSession which will be returned to the user as a
* AIDL remote object.
* #param sessionName Name of the session.
* #return A new instance of ILogDroidSession
*/
ILogDroidSession createSession(String sessionName) {
LogDroidSession session = new LogDroidSession(database, sessionName);
session.addLoggingOccurredListener(this);
return session;
}
/**
* Retrieves all session ids.
* #return Array containing all LogDroidSession ids.
*/
ArrayList<Integer> getSessionIds() {
return database.getSessionIds();
}
}
MainActivity.java (Relevant client code):
public class MainActivity extends Activity {
private ILogDroidSession session;
private ILogDroidBinder binder;
private ServiceConnection con = new ServiceConnection() {
public void onServiceConnected(ComponentName arg0, IBinder arg1) {
binder = ILogDroidBinder.Stub.asInterface(arg1); // always works
try {
// works locally but always returns null when cross-process
session = binder.startLogSession("TestSession");
// always works
List<Integer> ids = binder.getSessionIds();
} catch ( Exception ex) {
// no exceptions are thrown either when running locally or cross-process
Toast.makeText(getApplicationContext(), ex.getMessage(),
Toast.LENGTH_LONG).show();
}
}
public void onServiceDisconnected(ComponentName arg0) {
}
};
}
ILogDroidSession can be defined as just interface in java file, it shouldn't be in AIDL.
If the client and LogDroidService are running in different processes, LogDroidSession should be parcelable to send/receive over IPC.
Data that is exchanged across the processes should just be stream of bytes that both sender and receiver understands through a protocol.
I'm taking a wild guess and suppose my ILogDroidSession implementation should also implement Parcelable, but that wouldn't work, because I can't parcel an object containg a reference to an SQLiteDatabase (or can I?).
LogDroidSession can't be parceled here, add new functions to ILogDroidBinder that returns session related information (in the form of plain data types).

Communication between Android Java and Phonegap Javascript?

I believe that it's possible to call Java methods from (PhoneGap) Javascript.
Anyone knows how to do that?? (I know how to do it by changing the source code of PhoneGap, but I'd avoid that)
I finally made it work.
Create a class with methods you want to use:
public class MyClass {
private WebView mAppView;
private DroidGap mGap;
public MyClass(DroidGap gap, WebView view)
{
mAppView = view;
mGap = gap;
}
public String getTelephoneNumber(){
TelephonyManager tm =
(TelephonyManager) mGap.getSystemService(Context.TELEPHONY_SERVICE);
String number = tm.getLine1Number();
return number;
}
}
In your main activity add a Javascript interface for this class:
public class Main extends DroidGap
{
private MyClass mc;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
super.init();
mc = new MyClass(this, appView);
appView.addJavascriptInterface(mc, "MyCls");
super.loadUrl(getString(R.string.url));
}
}
In Javascript call window.MyCls methods:
<script>
$(function(){
$("#phone").text("My telephone number is: " +
window.MyCls.getTelephoneNumber());
});
</script>
Note:
As mentioned in the comment, for Android version 4.2 and above, add #JavascriptInterface to the method which you want to access from your HTML page. Reference.
addJavaScriptInterface(mc, "MyCls") without Gap init()ed may cause crush of the app, you'd better add super.init() before addJavascriptInterface()
public class Main extends DroidGap
{
private MyClass mc;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
super.init();
mc = new MyClass(this, appView);
appView.addJavascriptInterface(mc, "MyCls");
super.loadUrl(getString(R.string.url));
}
}
PhoneGap has a decent Plugin API. You'd write the plugin in Java by implementing the IPlugin interface. Most of the magic is in the execute() function.
public interface IPlugin {
/**
* Executes the request and returns PluginResult.
*
* #param action The action to execute.
* #param args JSONArry of arguments for the plugin.
* #param callbackId The callback id used when calling back into JavaScript.
* #return A PluginResult object with a status and message.
*/
PluginResult execute(String action, JSONArray args, String callbackId);
// ... more ...
}
The best way to start writing a plugin is by writing the javascript API first. You would typical start by writing a custom javascript class, and in each method on the javascript class, marshal the variables and call into the plugin you developed using the Phonegap.exec() method. Here is the method signature for your reference.
/* src/com/phonegap/api/PluginManager.java */
/**
* Receives a request for execution and fulfills it by finding the appropriate
* Java class and calling it's execute method.
*
* PluginManager.exec can be used either synchronously or async. In either case, a JSON encoded
* string is returned that will indicate if any errors have occurred when trying to find
* or execute the class denoted by the clazz argument.
*
* #param service String containing the service to run
* #param action String containt the action that the class is supposed to perform. This is
* passed to the plugin execute method and it is up to the plugin developer
* how to deal with it.
* #param callbackId String containing the id of the callback that is execute in JavaScript if
* this is an async plugin call.
* #param args An Array literal string containing any arguments needed in the
* plugin execute method.
* #param async Boolean indicating whether the calling JavaScript code is expecting an
* immediate return value. If true, either PhoneGap.callbackSuccess(...) or
* PhoneGap.callbackError(...) is called once the plugin code has executed.
*
* #return JSON encoded string with a response message and status.
*/
#SuppressWarnings("unchecked")
public String exec(final String service, final String action,
final String callbackId, final String jsonArgs,
final boolean async)
You also need to register the Plugin. You do this by adding the registration code at the bottom of your custom javascript library.
In the example below, the author defined a javascript BarcodeScanner class and registers it using the addConstructor method.
Two steps are carried out in the addConstructor:
Create a new instance of BarcodeScanner in javascript and registers it.
This is accessible in javascript as window.plugins.barcodeScanner
Registers the custom Plugin class with a service name. This service name
is passed in as the first argument to PhoneGap.exec so that PhoneGap
can instantiate the java plugin class and call the execute() method on it.
Sample registration code:
PhoneGap.addConstructor(function() {
/* The following registers an instance of BarcodeScanner in window.plugins.barcodeScanner */
PhoneGap.addPlugin('barcodeScanner', new BarcodeScanner());
/* The following associates a service name BarcodeScanner with a class com.beetight.barcodescanner.BarcodeScanner */
/* The service name is the first argument passed into PhoneGap.exec */
PluginManager.addService("BarcodeScanner","com.beetight.barcodescanner.BarcodeScanner");
});
a simpler form:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
super.init();
super.appView.getSettings().setJavaScriptEnabled(true);
super.appView.addJavascriptInterface(this, "MyCls");
super.loadUrl("file:///android_asset/www/login.html");
}
If anyone gets nullPointer exception using the code above, do super.oncreate() first and then super..init()
super.onCreate(savedInstanceState);
super.init();
I found this solution here: Phonegap Google Group
Thanks a lot to #zorglub76 for the solution....
Communication from JavaScript to native is achieved by overriding the JavaScript prompt function in the Android native code and the message passed is much like that used in iOS. We used to use WebView.addJavascriptInterface to add Java objects directly to the JavaScript sandbox but that was causing some devices to crash with Android 2.3. To call JavaScript from native we currently use WebView.loadUrl(”javascript:…”) but that has some problems so we are soon moving over to polling a Java message queue calling a local HTTP server via a long-lived XHR connection.
Description by here

Categories

Resources