If you set the build target of your project to 21 (Android 5) your application might stop compiling that is because Android 5 uses Java 1.7 whereas the rest uses 1.6.
public class MyFragment extends Fragment {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
...
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.menu_main, menu);
super.onCreateOptionsMenu(menu, inflater);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
// Handle the clicked menu option here
}
}
On an Activity (menu from scratch)
@Override
public boolean onCreateOptionsMenu(Menu menu) {
this.getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
// Handle the clicked menu option here
}
}
1) If you have a focusable view in your Layout of your list item the onItemClickListener won't get called. You can fix this issue by adding a "android:descendantFocusability="blocksDescendants"" to your list item layout container.
Create a base class from which your activities will inherit
public class AbstractActivity extends Activity {
...
@Override
protected void onCreate(Bundle arg0) {
super.onCreate(arg0);
setOrientationAccordingToDevice();
}
...
protected void setOrientationAccordingToDevice() {
if (ScreenHelper.isDeviceATablet(this)) {
// Since it is a tablet it will have an api > 8. So this is safe.
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
}
else {
// How do I implement the SCREEN_ORIENTATION_SENSOR_PORTRAIT functionality previous to api 9?
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
}
}
ScreenHelper
public class ScreenHelper {
public static boolean isDeviceATablet(Activity activity) {
DisplayMetrics metrics = new DisplayMetrics();
activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
int widthPixels = metrics.widthPixels;
int heightPixels = metrics.heightPixels;
float scaleFactor = metrics.density;
float widthDp = widthPixels / scaleFactor;
float heightDp = heightPixels / scaleFactor;
float smallestWidth = Math.min(widthDp, heightDp);
return (smallestWidth >= 600);
}
public static void hideSoftKeyboard(Activity activity, View view) {
InputMethodManager imm = (InputMethodManager) activity.getSystemService(Activity.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
}
public class DatabaseHelper extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "DATABASE_NAME";
private static final int SCHEMA_VERSION = 1;
...
private DatabaseHelper() {
super(ReportTvApplication.getContext(), DATABASE_NAME, null, SCHEMA_VERSION);
}
}
Pre-existing SQLite database file from the "assets" folder.
1. Preparing the SQLite database file.
Open your database and add a new table called "android_metadata":
CREATE TABLE "android_metadata" ("locale" TEXT DEFAULT 'en_US');
INSERT INTO "android_metadata" VALUES ('en_US');
Then, it is necessary to rename the primary id field of your tables to "_id" (or add a primary key field called "_id") so Android will know where to bind the id field of your tables.
2. Copying, opening and accessing your database in your Android application.
Now just put your database file in the "assets" folder of your project and create a Database Helper class by extending the SQLiteOpenHelper class from the "android.database.sqlite" package.
Make your DataBaseHelper class look like this:
public class DatabaseHelper extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "database.sql";
private SQLiteDatabase myDataBase;
private final Context myContext;
public DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, 1);
this.myContext = context;
}
public void createDataBase() throws IOException {
boolean dbExist = databaseExists();
if (dbExist) {
// do nothing - database already exist
} else {
this.getReadableDatabase();
try {
copyDataBase();
} catch (IOException e) {
throw new Error("Error copying database");
}
}
}
private boolean databaseExists() {
SQLiteDatabase checkDB = null;
try {
final String myPath = getDatabasePath();
checkDB = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READWRITE);
} catch (SQLiteException e) {
// database does't exist yet.
}
if (checkDB != null) {
checkDB.close();
}
return checkDB != null ? true : false;
}
private String getDatabasePath() {
final String myPath = myContext.getDatabasePath(DatabaseHelper.DATABASE_NAME)
.getAbsolutePath();
return myPath;
}
private void copyDataBase() throws IOException {
// Open your local db as the input stream
InputStream myInput = myContext.getAssets().open(DATABASE_NAME);
// Open the empty db as the output stream
OutputStream myOutput = new FileOutputStream(getDatabasePath());
// transfer bytes from the inputfile to the outputfile
byte[] buffer = new byte[1024];
int length;
while ((length = myInput.read(buffer)) > 0) {
myOutput.write(buffer, 0, length);
}
// Close the streams
myOutput.flush();
myOutput.close();
myInput.close();
}
public void openDataBase() throws SQLException {
// Open the database
myDataBase = SQLiteDatabase.openDatabase(getDatabasePath(), null,
SQLiteDatabase.OPEN_READWRITE);
}
@Override
public synchronized void close() {
if (myDataBase != null)
myDataBase.close();
super.close();
}
@Override
public void onCreate(SQLiteDatabase db) {
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
// Add your public helper methods to access and get content from the database.
// You could return cursors by doing "return myDataBase.query(....)" so it'd be easy
// to you to create adapters for your views.
}
Example query with distinct
public List<String> getSimulations() {
String[] projection = new String[] { SIMULATION_ID };
// The first boolean corresponds to distinct
Cursor cursor = getReadableDatabase().query(true, TABLE, projection, null, null, null, null, null, null);
return getSimulationsFromCursor(cursor);
}
private List<String> getSimulationsFromCursor(Cursor cursor) {
List<String> simulations = new ArrayList<String>();
// This is the safe way to check if the cursor has content
if (cursor == null || !cursor.moveToFirst()) {
return null;
}
// For whatever reason cursor.isLast() wasn't working for me, I could go past the last
for (int i = 0; i < cursor.getCount(); i++, cursor.moveToNext()) {
// The index belongs to the index of the field in the projection string
simulations .add(cursor.getString(0));
}
return scenarios;
}
1.1) Create a new source folder called "Test"
1.2) Create a subclass that either extends either "TestCase" or "AndroidTestCase"*
1.3) All method should be named like "public void testX()" where "X" is whatever you want.
1.4) In the manifest you need to add:
public class AllTests extends TestSuite {
public static Test suite() {
return new TestSuiteBuilder(AllTests.class).includeAllPackagesUnderHere().build();
}
}
1) When you create tabs the pager will create (at least), te current and the next. It is in times like this you may need to user "getUserVisibleHint()" method from the fragment which tells you whether the fragment is visible or not.
1) Run the SDK Manager.
2) Select "Android SDK Platform-tools" under "Tools" (if needed) and "Google USB Driver" under "Extras" (if needed)
3) Right click on "Computer" and select "Manage". Click on "Device manager". Alternatively click on Windows home button and search for "Device manager" and run it.
4) Expand the "Portable devices" tab. Right click on your device and then select the following "Update driver software" > "Browse my computer for driver software" > "Let me pick from a list of device driver on my computer" > "Have disk.." > "Browse" and go to your root android path "<android_sdk_path>/extras/google/usb_driver/android_winusb.inf" click "Next" and "Yes" to all following dialogs and you will be done.
package ar.com.fennoma.asi.tasks;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.AsyncTask;
import ar.com.fennoma.asi.R;
/**
* The downside of this class is that you have to override non-traditional
* methods rather than overriding: onPreExecute, onPostExecute, and
* doInBackground.
*/
public abstract class NetworkTask<Params, Progress, Result> extends
AsyncTask<Params, Progress, TaskResult> {
public interface ICallBack<Result> {
public void onError(Result result);
public void onSuccessful(Result result);
}
private ICallBack<TaskResult> callback;
protected Context context;
public NetworkTask(Context context, ICallBack<TaskResult> callback) {
this.context = context;
this.callback = callback;
}
// We won't let extending classes to override this method to prevent them
// from not calling the callback
@Override
protected final void onPostExecute(TaskResult response) {
if (callback != null) {
if (response.error) {
callback.onError(response);
} else {
callback.onSuccessful(response);
}
}
onPostProcessing(response);
}
protected void onPostProcessing(TaskResult response) {
}
// We won't let extending classes to override this method to prevent them
// from skipping the check
@Override
protected final TaskResult doInBackground(final Params... params) {
try {
if (context == null) {
throw new IllegalArgumentException("Context cannot be null");
}
if (deviceHasAnActiveConnection()) {
return this.doOnActiveConnection(params);
} else {
doOnNoActiveConnection(params);
return createNoConnectionResult();
}
} catch (final Exception e) {
doOnException(e, params);
return createExceptionResult(e);
}
}
private TaskResult createNoConnectionResult() {
TaskResult taskResult = new TaskResult();
taskResult.error = true;
taskResult.exception = false;
taskResult.message = context.getString(R.string.no_connection);
return taskResult;
}
private TaskResult createExceptionResult(Exception e) {
TaskResult taskResult = new TaskResult();
taskResult.error = true;
taskResult.exception = true;
taskResult.message = context.getString(R.string.exception);
return taskResult;
}
private boolean deviceHasAnActiveConnection() {
ConnectivityManager systemService = (ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetworkInfo = systemService.getActiveNetworkInfo();
return (activeNetworkInfo != null) && activeNetworkInfo.isConnected()
&& activeNetworkInfo.isAvailable();
}
protected abstract TaskResult doOnActiveConnection(Params... params) throws Exception;
// Hook methods
/**
* The callback will be called on "onPostExecute" so there is no need to do
* it in here.
*
* @param params
*/
protected void doOnNoActiveConnection(Params... params) {
}
/**
* The callback will be called on "onPostExecute" so there is no need to do
* it in here.
*
* @param params
*/
protected void doOnException(Exception e, Params... params) {
}
}
You will need to add the following permission to the manifest:
public class DashedBox extends View {
private Paint paint;
public DetectionRectangle(Context context) {
super(context);
createPaint();
}
private void createPaint() {
paint = new Paint();
paint.setColor(Color.WHITE);
paint.setStyle(Style.STROKE);
paint.setStrokeWidth(convertToPx(2));
paint.setPathEffect(new DashPathEffect(new float[] { 20, 5 }, 0));
setLayerType(View.LAYER_TYPE_SOFTWARE, null); // Mandatory else it won't draw the dash but a full line
}
private int convertToPx(int dp) {
// Get the screen's density scale
final float scale = getResources().getDisplayMetrics().density;
// Convert the dps to pixels, based on density scale
return (int) (dp * scale + 0.5f);
}
public DetectionRectangle(Context context, AttributeSet attrs) {
super(context, attrs);
createPaint();
}
public DetectionRectangle(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
createPaint();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawLine(0, 0, getWidth(), 0, paint); // Top line
canvas.drawLine(0, 0, 0, getHeight(), paint); // Left line
canvas.drawLine(0, getHeight(), getWidth(), getHeight(), paint); // Bot line
canvas.drawLine(getWidth(), 0, getWidth(), getHeight(), paint); // Right line
}
}
public int convertToPx(int dp) {
// Get the screen's density scale
final float scale = getResources().getDisplayMetrics().density;
// Convert the dps to pixels, based on density scale
return (int) (dp * scale + 0.5f);
}
public class GenderAdapter extends BaseAdapter {
private Context context;
private String[] genderList;
public GenderAdapter(Context context) {
this.context = context;
this.genderList = new String[3];
this.genderList[0] = context.getString(R.string.gender); // Hint text
this.genderList[1] = context.getString(R.string.male);
this.genderList[2] = context.getString(R.string.female);
}
@Override
public View getDropDownView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = LayoutInflater.from(context).inflate(R.layout.drop_down_row_light_gray, null);
}
TextView text = (TextView) convertView.findViewById(R.id.text);
text.setText(getItem(position));
Resources resources = context.getResources();
text.setTextColor(resources.getColor(position == 0 ? R.color.gray : R.color.dark_gray)); // If it is the hint text (position == 0) set the textcolor to be a lighter color
return convertView;
}
@Override
public int getCount() {
return genderList.length;
}
@Override
public String getItem(int position) {
return genderList[position];
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = LayoutInflater.from(context).inflate(R.layout.closed_row_light_gray, null);
}
TextView text = (TextView) convertView.findViewById(R.id.text);
text.setText(getItem(position));
Resources resources = context.getResources();
text.setTextColor(resources.getColor(position == 0 ? R.color.gray : R.color.dark_gray)); // If it is the hint text (position == 0) set the textcolor to be a lighter color
return convertView;
}
}
private void setSubmitButtonOnClickListener() {
submitButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (isFormValid()) {
...
} else {
if (isAgeEmpty()) {
TextView textView = (TextView) ageSpinner.getSelectedView().findViewById(R.id.text); // "text" is the layout id of the TextView that displays the text
textView.setError(getString(R.string.age_is_required));
}
...
}
}
});
}
Notes:
1) In my experience, when I used 9 patch as the spinne's background, the spinner's text dissapeared. It does not happen if I use a "normal" drawable or background color.
2) The "arrow thingy" to the right side of a spinner is actually a background (a 9 patch png). That being said, if you change the spinne background the arrow will dissapear.ng>
Note: This can be used with facebook if the application is installed.
* If you leave out the flag, when returning to your app (from homescreen, from recents etc.), you would see the Activity of the share target (messaging/mailing/IM app) instead of yours.
To be able to compile JNI code you need to create a make file. You can fin examples of working make files in the samples here. I named the Vuforia Android samples since it was because of this library that I had to work with JNI :P
In windows you just have to type the following the commands promt:
cd <path_to_jni_files>
<path_to_android_ndk>\ndk-build
For example:
cd C:\Users\dev\Desktop\Repositories\MyProject\jni
C:\android-ndk-r9c\ndk-build
You can find the Android NDK here. You can find the oficial documentation about JNI here.
Loading libs
The compiled library needs to be placed inside "/libs" inside, most likely, the folder named "armeabi-v7a".
For example, to load the library named "libdetection_based_tracker.so" somewhere in your code you have to call the following method: "System.loadLibrary("detection_based_tracker");".
1) We first need to find the class will be working on, in this case, the float class. env is the environment pointer is of type (JNIEnv).
2) Get the constructor method.
<init> indicates its a constructor.
(F)V defines the constructor arguments (the characters inside the parentheses) and the return type (just after the parentheses). In this case the arguments is just a single float (F) and the return type is void (V). You can check all type signatures here.
3) Create a java object given the class (floatClass), the constructor (floatConstructor) and the arguments of the constructor is 5.0.