I have an app that works fine on older Android versions, however, on later (Android 11> onwards) whilst the camera(take photo) function works fine, and permissions are OK I can't use the PhotoPicker function, it just shows blank picker , before crashing out of the app completely - in older devices the photo gallery of the device displays correctly and allows you to select a photo to use.
Here is the onCreate for the
PhotoPickerActivity.java
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
requestWindowFeature(1);
getWindow().setFlags(1024, 1024);
boolean booleanExtra = getIntent().getBooleanExtra(PhotoPicker.EXTRA_SHOW_CAMERA, true);
boolean booleanExtra2 = getIntent().getBooleanExtra(PhotoPicker.EXTRA_SHOW_GIF, false);
boolean booleanExtra3 = getIntent().getBooleanExtra(PhotoPicker.EXTRA_PREVIEW_ENABLED, true);
this.forwardMain = getIntent().getBooleanExtra(PhotoPicker.MAIN_ACTIVITY, false);
setShowGif(booleanExtra2);
setContentView(R.layout.__picker_activity_photo_picker);
setSupportActionBar((Toolbar) findViewById(R.id.toolbar));
setTitle(getResources().getString(R.string.tap_to_select));
ActionBar supportActionBar = getSupportActionBar();
supportActionBar.setDisplayHomeAsUpEnabled(true);
// if (Build.VERSION.SDK_INT >= 21) {
supportActionBar.setElevation(25.0f);
// }
this.maxCount = getIntent().getIntExtra(PhotoPicker.EXTRA_MAX_COUNT, 9);
int intExtra = getIntent().getIntExtra(PhotoPicker.EXTRA_GRID_COLUMN, 3);
this.originalPhotos = getIntent().getStringArrayListExtra(PhotoPicker.EXTRA_ORIGINAL_PHOTOS);
this.pickerFragment = (PhotoPickerFragment) getSupportFragmentManager().findFragmentByTag("tag");
if (this.pickerFragment == null) {
this.pickerFragment = PhotoPickerFragment.newInstance(booleanExtra, booleanExtra2, booleanExtra3, intExtra, this.maxCount, this.originalPhotos);
getSupportFragmentManager().beginTransaction().replace(R.id.container, this.pickerFragment, "tag").commit();
getSupportFragmentManager().executePendingTransactions();
}
this.pickerFragment.getPhotoGridAdapter().setOnItemCheckListener(new OnItemCheckListener() {
#Override
public final boolean onItemCheck(int i, Photo photo, int i2) {
return PhotoPickerActivity.this.lambda$onCreate$0$PhotoPickerActivity(i, photo, i2);
}
});
}
We also have PhotoPicker.java
public class PhotoPicker {
public static final int DEFAULT_COLUMN_NUMBER = 3;
public static final int DEFAULT_MAX_COUNT = 9;
public static final String EXTRA_GRID_COLUMN = "column";
public static final String EXTRA_MAX_COUNT = "MAX_COUNT";
public static final String EXTRA_ORIGINAL_PHOTOS = "ORIGINAL_PHOTOS";
public static final String EXTRA_PREVIEW_ENABLED = "PREVIEW_ENABLED";
public static final String EXTRA_SHOW_CAMERA = "SHOW_CAMERA";
public static final String EXTRA_SHOW_GIF = "SHOW_GIF";
public static final String KEY_SELECTED_PHOTOS = "SELECTED_PHOTOS";
public static final String MAIN_ACTIVITY = "MAIN_ACTIVITY";
public static final int REQUEST_CODE = 233;
public static PhotoPickerBuilder builder() {
return new PhotoPickerBuilder();
}
public static class PhotoPickerBuilder {
private Intent mPickerIntent = new Intent();
private Bundle mPickerOptionsBundle = new Bundle();
public void start(Activity activity, int i) {
if (PermissionsUtils.checkReadStoragePermission(activity)) {
activity.startActivityForResult(getIntent(activity), i);
}
}
public void start(Context context, Fragment fragment, int i) {
if (PermissionsUtils.checkReadStoragePermission(fragment.getActivity())) {
fragment.startActivityForResult(getIntent(context), i);
}
}
public void start(Context context, Fragment fragment) {
if (PermissionsUtils.checkReadStoragePermission(fragment.getActivity())) {
fragment.startActivityForResult(getIntent(context), PhotoPicker.REQUEST_CODE);
}
}
public Intent getIntent(Context context) {
this.mPickerIntent.setClass(context, PhotoPickerActivity.class);
this.mPickerIntent.putExtras(this.mPickerOptionsBundle);
return this.mPickerIntent;
}
public void start(Activity activity) {
start(activity, PhotoPicker.REQUEST_CODE);
}
public PhotoPickerBuilder setPhotoCount(int i) {
this.mPickerOptionsBundle.putInt(PhotoPicker.EXTRA_MAX_COUNT, i);
return this;
}
public PhotoPickerBuilder setGridColumnCount(int i) {
this.mPickerOptionsBundle.putInt(PhotoPicker.EXTRA_GRID_COLUMN, i);
return this;
}
public PhotoPickerBuilder setShowGif(boolean z) {
this.mPickerOptionsBundle.putBoolean(PhotoPicker.EXTRA_SHOW_GIF, z);
return this;
}
public PhotoPickerBuilder setShowCamera(boolean z) {
this.mPickerOptionsBundle.putBoolean(PhotoPicker.EXTRA_SHOW_CAMERA, z);
return this;
}
public PhotoPickerBuilder setSelected(ArrayList<String> arrayList) {
this.mPickerOptionsBundle.putStringArrayList(PhotoPicker.EXTRA_ORIGINAL_PHOTOS, arrayList);
return this;
}
public PhotoPickerBuilder setForwardMain(boolean z) {
this.mPickerOptionsBundle.putBoolean(PhotoPicker.MAIN_ACTIVITY, z);
return this;
}
public PhotoPickerBuilder setPreviewEnabled(boolean z) {
this.mPickerOptionsBundle.putBoolean(PhotoPicker.EXTRA_PREVIEW_ENABLED, z);
return this;
}
}
}
In the AndroidManifest.xml the permissions for Camera are there, and on runtime are checked, and permission is granted.
Related
I know that there are countless examples of this on the internet, but for some reason I can't get this to work in the particular code I'm working on, despite all the resources/answers I've read through. And I don't have anyone with Java skills around me to help out. So hopefully that changes here.
I'm updating an existing Android media picker plugin (for a cordova app) to make it show video thumbnails in addition to pictures in the device gallery. I'm stuck with a "non-static variable in static context" error, but I'm having a really hard time identifying what needs to be changed. Below is the meat of the code I have. I have removed some parts to hopefully focus on the relevant bits. Essentially, the error occurs inside decodeSampledBitmapFromUri when I'm trying to get the thumbnail of a video. The method I'm using is MediaStore.Video.Thumbnails.getThumbnail and its first argument is the context, which is where the error starts. You can see that in loadThumbnail I tried getting the context using cordova.getActivity() and then passing it to decodeSampledBitmapFromUri, but even inside loadThumbnail I'm still getting the non-static error. I'm not sure how to proceed from here (I'm very new to Java). This is the code (with some other parts stripped out because I think they're not relevant):
public class MediaPicker extends CordovaPlugin {
private static final String HEIGHT = "height";
private static final String COLUMNS = "columns";
private static final String SELECTION_LIMIT = "selectionLimit";
private MediaPickerView view;
public static int getResourceId(Context context, String group, String key) {
return context.getResources().getIdentifier(key, group, context.getPackageName());
}
public static int DP2PX(Context context, float dipValue) {
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
return (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dipValue, metrics);
}
#Override
public void initialize(CordovaInterface cordova, CordovaWebView webView) {
super.initialize(cordova, webView);
}
#Override
public boolean execute(String action, JSONArray data, CallbackContext callbackContext) throws JSONException {
if (action.equals("display")) {
JSONObject store = data.getJSONObject(0);
double height = Double.parseDouble(store.getString(HEIGHT));
int columns = Integer.parseInt(store.getString(COLUMNS));
int selectionLimit = Integer.parseInt(store.getString(SELECTION_LIMIT));
display(height, columns, selectionLimit, callbackContext);
return true;
} else {
return false;
}
}
private void display(final double height, final int columns, final int selectionLimit, final CallbackContext callbackContext) {
cordova.getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
if (view == null) {
view = new MediaPickerView(cordova.getActivity());
}
view.setOptions(height, columns, selectionLimit, callbackContext);
view.load();
cordova.getActivity().addContentView(view,
new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT));
}
});
}
public static class MediaPickerView extends FrameLayout implements StateController {
private GridView grid;
private View balanceView;
private int selectionLimit;
private CallbackContext callbackContext;
private TreeMap<Integer, PictureInfo> selection = new TreeMap();
public MediaPickerView(Context context) {
super(context);
init();
}
public MediaPickerView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
LayoutInflater.from(getContext()).inflate(getResourceId(getContext(), "layout", "view_media"), this);
grid = (GridView)findViewById(getResourceId(getContext(), "id", "gridView"));
balanceView = findViewById(getResourceId(getContext(), "id", "vBalancer"));
}
public void setOptions(double height, int columns, int selectionLimit, CallbackContext callbackContext) {
this.selectionLimit = selectionLimit;
this.callbackContext = callbackContext;
grid.setNumColumns(columns);
LinearLayout.LayoutParams glp = (LinearLayout.LayoutParams) grid.getLayoutParams();
glp.weight = (float) height;
LinearLayout.LayoutParams blp = (LinearLayout.LayoutParams) balanceView.getLayoutParams();
blp.weight = (float) (1 - height);
requestLayout();
}
public void load() {
final GridAdapter adapter = new GridAdapter(getContext(), this);
grid.setAdapter(adapter);
new Thread() {
#Override
public void run() {
final String[] columns = new String[]{
MediaStore.Video.VideoColumns._ID,
MediaStore.Video.VideoColumns.DATA,
MediaStore.Video.VideoColumns.BUCKET_DISPLAY_NAME,
MediaStore.Video.VideoColumns.DISPLAY_NAME,
MediaStore.Video.VideoColumns.DATE_TAKEN,
MediaStore.Video.VideoColumns.MIME_TYPE,
MediaStore.Files.FileColumns.MEDIA_TYPE};
final String orderBy = MediaStore.Video.VideoColumns.DATE_TAKEN
+ " DESC";
final String selection = MediaStore.Files.FileColumns.MEDIA_TYPE + "="
+ MediaStore.Files.FileColumns.MEDIA_TYPE_VIDEO;
Uri queryUri = MediaStore.Files.getContentUri("external");
final Cursor cursor = getContext().getContentResolver().query(
queryUri,
columns,
selection, // Which rows to return (all rows)
null, // Selection arguments (none)
orderBy);
if (cursor.moveToFirst()) {
adapter.setCursor(cursor);
}
}
}.start();
}
}
public static class MediaCache extends LruCache<String, Bitmap> {
public MediaCache(int maxSize) {
super(maxSize);
}
#Override
protected int sizeOf(String key, Bitmap value) {
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
return value.getAllocationByteCount();
}
return value.getByteCount();
}
}
public static class GridAdapter extends BaseAdapter implements AsyncPictureLoader{
private Cursor cursor;
private Executor executor = Executors.newFixedThreadPool(4);
private MediaCache pictureCache;
private int dataColumn;
private StateController stateController;
private ArrayList<PictureView> createdViews = new ArrayList<PictureView>();
public GridAdapter(Context context, StateController stateController) {
this.stateController = stateController;
int memClass = ( (ActivityManager)context.getSystemService( Context.ACTIVITY_SERVICE ) ).getMemoryClass();
int cacheSize = 1024 * 1024 * memClass / 10;
pictureCache = new MediaCache(cacheSize);
}
#Override
public int getCount() {
return cursor != null ? cursor.getCount() : 0;
}
#Override
public Object getItem(int position) {
return null;
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
PictureView view;
if (convertView != null) {
view = (PictureView) convertView;
} else {
view = new PictureView(pictureCache, parent.getContext(), this, stateController);
createdViews.add(view);
}
view.load(position);
return view;
}
public void setCursor(Cursor cursor) {
this.cursor = cursor;
dataColumn = cursor
.getColumnIndex(MediaStore.Video.VideoColumns.DATA);
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
notifyDataSetChanged();
}
});
}
#Override
public void loadThumbnail(final PictureInfo pictureInfo, final AsyncPictureLoaderCallback callback) {
if (cursor == null) {
return;
}
executor.execute(new Runnable() {
#Override
public void run() {
if (cursor == null || pictureInfo.cancelled) {
return;
}
synchronized (cursor) {
cursor.moveToPosition(pictureInfo.position);
pictureInfo.uri = cursor.getString(dataColumn);
}
if (pictureInfo.uri == null) {
return;
}
synchronized (pictureCache) {
Bitmap cachedBitmap = pictureCache.get(pictureInfo.uri);
if (cachedBitmap != null) {
pictureInfo.thumbnail = cachedBitmap;
callback.onLoad(pictureInfo);
return;
}
}
int thumbSideSize = callback.getThumbnailSideSize();
if (thumbSideSize <= 0) {
thumbSideSize = 128;
}
// the next 4 variables are needed for videos, see https://stackoverflow.com/a/29555484/7987987
int type = cursor.getColumnIndex(MediaStore.Files.FileColumns.MEDIA_TYPE);
int tInt = cursor.getInt(type);
int colId = cursor.getColumnIndex(MediaStore.Video.VideoColumns._ID);
int id = cursor.getInt(colId);
pictureInfo.thumbnail = decodeSampledBitmapFromUri(pictureInfo.uri, thumbSideSize, thumbSideSize, tInt, id, cordova.getActivity());
if (pictureInfo.thumbnail != null) {
callback.onLoad(pictureInfo);
synchronized (pictureCache) {
pictureCache.put(pictureInfo.uri, pictureInfo.thumbnail);
}
} else {
}
}
});
}
private Bitmap decodeSampledBitmapFromUri(String path, int reqWidth, int reqHeight, int typeInt, int id, Context context) {
Bitmap bm = null;
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
if (typeInt == 3) {
// this is a video, handle according to https://stackoverflow.com/a/29555484/7987987
// using BitmapFactory options as seen in the link above
options.inSampleSize = 4; // hardcoded for now until this works, then I'll make it dynamic
options.inPurgeable = true;
bm = MediaStore.Video.Thumbnails.getThumbnail(
context.getContentResolver(), id,
MediaStore.Video.Thumbnails.MINI_KIND, options);
} else {
// this is an image
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(path, options);
// Calculate inSampleSize
options.inSampleSize = calculateSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
bm = BitmapFactory.decodeFile(path, options);
}
return bm;
}
public int calculateSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
if (width > height) {
inSampleSize = Math.round((float)height / (float)reqHeight);
} else {
inSampleSize = Math.round((float)width / (float)reqWidth);
}
}
return inSampleSize;
}
}
public interface AsyncPictureLoader {
void loadThumbnail(PictureInfo position, AsyncPictureLoaderCallback callback);
}
public interface AsyncPictureLoaderCallback {
void onLoad(PictureInfo picture);
int getThumbnailSideSize();
}
public interface StateController {
// stuff here that controls selection
}
public static class PictureInfo {
public int position;
public String uri;
public Bitmap thumbnail;
public volatile boolean cancelled = false;
}
public static class PictureView extends FrameLayout implements AsyncPictureLoaderCallback, CompoundButton.OnCheckedChangeListener {
private final AsyncPictureLoader loader;
private final CheckBox checkBox;
private final StateController stateController;
private final MediaCache pictureCache;
private ImageView vImage;
private PictureInfo pictureInfo;
public PictureView(MediaCache pictureCache, Context context, AsyncPictureLoader loader, StateController stateController) {
super(context);
this.pictureCache = pictureCache;
this.loader = loader;
this.stateController = stateController;
LayoutInflater.from(getContext()).inflate(getResourceId(getContext(), "layout", "view_media_item"), this);
vImage = (ImageView)findViewById(getResourceId(getContext(), "id", "vImage"));
checkBox = (CheckBox)findViewById(getResourceId(getContext(), "id", "checkBox"));
}
public void load(int position) {
if (pictureInfo != null) {
pictureInfo.cancelled = true;
}
pictureInfo = new PictureInfo();
pictureInfo.position = position;
pictureInfo.thumbnail = null;
pictureInfo.uri = null;
vImage.setImageResource(0);
vImage.setVisibility(INVISIBLE);
loader.loadThumbnail(pictureInfo, this);
updateSelection();
}
#Override
public void onLoad(PictureInfo picture) {
if (this.pictureInfo != picture) {
return;
}
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
vImage.setImageBitmap(pictureInfo.thumbnail);
vImage.setVisibility(VISIBLE);
}
});
}
}
}
I am developing a chat app and I want to save user chat history and messages using room database. By this, when the users start the app they can see their previous history and messages.
Below my User.java model class where implemented user model properties.
#Entity
public class User implements IChatUser {
#PrimaryKey(autoGenerate = true)
private Integer id;
#ColumnInfo(name = "name")
String name;
#Ignore
Bitmap icon;
public User() {
}
public User(int id, String name, Bitmap icon) {
this.id = id;
this.name = name;
this.icon = icon;
}
#Override
public String getId() {
return this.id.toString();
}
#Override
public String getName() {
return this.name;
}
public void setId(Integer id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
#Override
public Bitmap getIcon() {
return this.icon;
}
#Override
public void setIcon(Bitmap icon) {
this.icon = icon;
}
}
UserDao.java
#Dao
public interface UserDao {
#Query("SELECT * FROM user")
List<User> getUsers();
#Insert
void insert(User user);
#Delete
void delete(User user);
#Update
void update(User user);
}
UserRoomDatabase.java
#Database(entities = {User.class}, version = 1)
public abstract class UserRoomDatabase extends RoomDatabase {
public abstract UserDao userDao();
}
MessengerActivity.java
public class MessengerActivity extends Activity{
#VisibleForTesting
protected static final int RIGHT_BUBBLE_COLOR = R.color.colorPrimaryDark;
#VisibleForTesting
protected static final int LEFT_BUBBLE_COLOR = R.color.gray300;
#VisibleForTesting
protected static final int BACKGROUND_COLOR = R.color.blueGray400;
#VisibleForTesting
protected static final int SEND_BUTTON_COLOR = R.color.blueGray500;
#VisibleForTesting
protected static final int SEND_ICON = R.drawable.ic_action_send;
#VisibleForTesting
protected static final int OPTION_BUTTON_COLOR = R.color.teal500;
#VisibleForTesting
protected static final int RIGHT_MESSAGE_TEXT_COLOR = Color.WHITE;
#VisibleForTesting
protected static final int LEFT_MESSAGE_TEXT_COLOR = Color.BLACK;
#VisibleForTesting
protected static final int USERNAME_TEXT_COLOR = Color.WHITE;
#VisibleForTesting
protected static final int SEND_TIME_TEXT_COLOR = Color.WHITE;
#VisibleForTesting
protected static final int DATA_SEPARATOR_COLOR = Color.WHITE;
#VisibleForTesting
protected static final int MESSAGE_STATUS_TEXT_COLOR = Color.WHITE;
#VisibleForTesting
protected static final String INPUT_TEXT_HINT = "New message..";
#VisibleForTesting
protected static final int MESSAGE_MARGIN = 5;
private ChatView mChatView;
private MessageList mMessageList;
private ArrayList<User> mUsers;
private int mReplyDelay = -1;
Realm realm;
private static final int READ_REQUEST_CODE = 100;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_messenger);
initUsers();
mChatView = findViewById(R.id.chat_view);
//Load saved messages
loadMessages(realm);
//Set UI parameters if you need
mChatView.setRightBubbleColor(ContextCompat.getColor(this,RIGHT_BUBBLE_COLOR));
mChatView.setLeftBubbleColor(ContextCompat.getColor(this, LEFT_BUBBLE_COLOR));
mChatView.setBackgroundColor(ContextCompat.getColor(this, BACKGROUND_COLOR));
mChatView.setSendButtonColor(ContextCompat.getColor(this, SEND_BUTTON_COLOR));
mChatView.setSendIcon(SEND_ICON);
mChatView.setOptionIcon(R.drawable.ic_account_circle);
mChatView.setOptionButtonColor(OPTION_BUTTON_COLOR);
mChatView.setRightMessageTextColor(RIGHT_MESSAGE_TEXT_COLOR);
mChatView.setLeftMessageTextColor(LEFT_MESSAGE_TEXT_COLOR);
mChatView.setUsernameTextColor(USERNAME_TEXT_COLOR);
mChatView.setSendTimeTextColor(SEND_TIME_TEXT_COLOR);
mChatView.setDateSeparatorColor(DATA_SEPARATOR_COLOR);
mChatView.setMessageStatusTextColor(MESSAGE_STATUS_TEXT_COLOR);
mChatView.setInputTextHint(INPUT_TEXT_HINT);
mChatView.setMessageMarginTop(MESSAGE_MARGIN);
mChatView.setMessageMarginBottom(MESSAGE_MARGIN);
mChatView.setMaxInputLine(5);
mChatView.setUsernameFontSize(getResources().getDimension(R.dimen.font_small));
mChatView.setInputType(InputType.TYPE_TEXT_FLAG_CAP_SENTENCES);
mChatView.setInputTextColor(ContextCompat.getColor(this, R.color.red500));
mChatView.setInputTextSize(TypedValue.COMPLEX_UNIT_SP, 20);
mChatView.setOnBubbleClickListener(new Message.OnBubbleClickListener() {
#Override
public void onClick(Message message) {
mChatView.updateMessageStatus(message, MyMessageStatusFormatter.STATUS_SEEN);
Toast.makeText(
MessengerActivity.this,
"click : " + message.getUser().getName() + " - " + message.getText(),
Toast.LENGTH_SHORT
).show();
}
});
mChatView.setOnIconClickListener(new Message.OnIconClickListener() {
#Override
public void onIconClick(Message message) {
Toast.makeText(
MessengerActivity.this,
"click : icon " + message.getUser().getName(),
Toast.LENGTH_SHORT
).show();
}
});
mChatView.setOnIconLongClickListener(new Message.OnIconLongClickListener() {
#Override
public void onIconLongClick(Message message) {
Toast.makeText(
MessengerActivity.this,
"Removed this message \n" + message.getText(),
Toast.LENGTH_SHORT
).show();
mChatView.getMessageView().remove(message);
}
});
//Click Send Button
mChatView.setOnClickSendButtonListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
initUsers();
//new message
Message message = new Message.Builder()
.setUser(mUsers.get(0))
.setRight(true)
.setText(mChatView.getInputText())
.hideIcon(true)
.setStatusIconFormatter(new MyMessageStatusFormatter(MessengerActivity.this))
.setStatusTextFormatter(new MyMessageStatusFormatter(MessengerActivity.this))
.setStatusStyle(Message.Companion.getSTATUS_ICON())
.setStatus(MyMessageStatusFormatter.STATUS_DELIVERED)
.build();
//Set to chat view
mChatView.send(message);
//Add message list
mMessageList.add(message);
//Reset edit text
mChatView.setInputText("");
receiveMessage(message.getText());
}
});
//Click option button
mChatView.setOnClickOptionButtonListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
showDialog();
}
});
}
private void openGallery() {
Intent intent;
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
intent = new Intent(Intent.ACTION_GET_CONTENT);
} else {
intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
}
intent.setType("image/*");
startActivityForResult(intent, READ_REQUEST_CODE);
}
private void receiveMessage(String sendText) {
//Ignore hey
if (!sendText.contains("hey")) {
//Receive message
final Message receivedMessage = new Message.Builder()
.setUser(mUsers.get(1))
.setRight(false)
.setText(ChatBot.INSTANCE.talk(mUsers.get(0).getName(), sendText))
.setStatusIconFormatter(new MyMessageStatusFormatter(MessengerActivity.this))
.setStatusTextFormatter(new MyMessageStatusFormatter(MessengerActivity.this))
.setStatusStyle(Message.Companion.getSTATUS_ICON())
.setStatus(MyMessageStatusFormatter.STATUS_DELIVERED)
.build();
if (sendText.equals( Message.Type.PICTURE.name())) {
receivedMessage.setText("Nice!");
}
// This is a demo bot
// Return within 3 seconds
if (mReplyDelay < 0) {
mReplyDelay = (new Random().nextInt(4) + 1) * 1000;
}
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
mChatView.receive(receivedMessage);
//Add message list
mMessageList.add(receivedMessage);
}
}, mReplyDelay);
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode != READ_REQUEST_CODE || resultCode != RESULT_OK || data == null) {
return;
}
Uri uri = data.getData();
try {
Bitmap picture = MediaStore.Images.Media.getBitmap(getContentResolver(), uri);
Message message = new Message.Builder()
.setRight(true)
.setText(Message.Type.PICTURE.name())
.setUser(mUsers.get(0))
.hideIcon(true)
.setPicture(picture)
.setType(Message.Type.PICTURE)
.setStatusIconFormatter(new MyMessageStatusFormatter(MessengerActivity.this))
.setStatusStyle(Message.Companion.getSTATUS_ICON())
.setStatus(MyMessageStatusFormatter.STATUS_DELIVERED)
.build();
mChatView.send(message);
//Add message list
mMessageList.add(message);
receiveMessage(Message.Type.PICTURE.name());
} catch (IOException e) {
e.printStackTrace();
Toast.makeText(this, getString(R.string.error), Toast.LENGTH_SHORT).show();
}
}
private void initUsers() {
mUsers = new ArrayList<>();
//User id
int myId = 0;
//User icon
Bitmap myIcon = BitmapFactory.decodeResource(getResources(), R.drawable.face_2);
//User name
String myName = "Michael";
int yourId = 1;
Bitmap yourIcon = BitmapFactory.decodeResource(getResources(), R.drawable.face_1);
String yourName = "Emily";
final User me = new User(myId, myName, myIcon);
final User you = new User(yourId, yourName, yourIcon);
mUsers.add(me);
mUsers.add(you);
}
/**
* Load saved messages
* #param realm
*/
private void loadMessages(Realm realm) {
List<Message> messages = new ArrayList<>();
mMessageList = AppData.getMessageList(this);
if (mMessageList == null) {
mMessageList = new MessageList();
} else {
for (int i = 0; i < mMessageList.size(); i++) {
Message message = mMessageList.get(i);
//Set extra info because they were removed before save messages.
for (IChatUser user : mUsers) {
if (message.getUser().getId().equals(user.getId())) {
message.getUser().setIcon(user.getIcon());
}
}
if (!message.isDateCell() && message.isRight()) {
message.hideIcon(true);
}
message.setStatusStyle(Message.Companion.getSTATUS_ICON_RIGHT_ONLY());
message.setStatusIconFormatter(new MyMessageStatusFormatter(this));
message.setStatus(MyMessageStatusFormatter.STATUS_DELIVERED);
messages.add(message);
}
}
MessageView messageView = mChatView.getMessageView();
messageView.init(messages);
messageView.setSelection(messageView.getCount() - 1);
}
#Override
public void onResume() {
super.onResume();
initUsers();
}
#Override
public void onPause() {
super.onPause();
//Save message
mMessageList = new MessageList();
mMessageList.setMessages(mChatView.getMessageView().getMessageList());
AppData.putMessageList(this, mMessageList);
}
#VisibleForTesting
public ArrayList<User> getUsers() {
return mUsers;
}
public void setReplyDelay(int replyDelay) {
mReplyDelay = replyDelay;
}
private void showDialog() {
final String[] items = {
getString(R.string.send_picture),
getString(R.string.clear_messages)
};
new AlertDialog.Builder(this)
.setTitle(getString(R.string.options))
.setItems(items, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int position) {
switch (position) {
case 0 :
openGallery();
break;
case 1:
mChatView.getMessageView().removeAll();
break;
}
}
})
.show();
}
}
You should create a new room database to store your messages. It's table should look like this:
id
message
sendingUser
receivingUser
0
Hello how are you?
John
David
1
Thanks, im good.
David
John
2
good to hear that!
John
David
First create a new Message class. This class should look like this:
#Entity(tableName = "message_table")
data class Message(
#PrimaryKey(autoGenerate = true)
var id: Int,
#ColumnInfo(name= "message")
var message: String,
#ColumnInfo(name = "sendingUser")
var sendingUser: String,
#ColumnInfo(name = "receivingUser")
var receivingUser: String
)
Then create your MessageDatabase, like this:
#Database(entities = [Message::class], version = 1)
abstract class MessageDatabase: RoomDatabase() {
abstract fun messageDao(): MessageDao
}
Next create your MessageDao
#Dao
interface MessageDao {
#Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insert(message: Message)
#Query("SELECT ALL * FROM message_table WHERE sendingUser= :sendingUser")
suspend fun getMessageListFromSender(sendingUser: String): MutableList<Message>
#Query("SELECT ALL * FROM message_table")
suspend fun getMessageList(): MutableList<Message>
#Delete
suspend fun delete(message: Message)
#Update
suspend fun update(message: Message)
}
At last you can initialize your room database like this:
private val roomDb = Room.databaseBuilder(
getApplication(),
MessageDatabase::class.java, "message_database"
).build()
private val messageDao = roomDb.messageDao()
Use messageDao, to make operations with the database, this example shows you how to get message list from a certain sender:
suspend fun getMessageListFromSender(sendingUser: String): MutableList<Message> {
var list : MutableList<Message>
with (messageDao) {
list = this.getMessageListFromSender(sendingUser)
}
return list
}
viewModelScope.launch {
getMessageListFromSender("John")
}
I would appreciate some help with this current problem. I think I understand the cause of the issue, however I have no idea how to fix it. I have two custom views, one implements a ViewGroup and the other just a View.
CameraSourcePreview and GraphicOverlay
However they are both generic to T where T : GraphicOverlay<\T>.Graphic
In BarcodeFragmentActivity. Line 64.
SetContentView(Resource.Layout.Barcode_Capture)
Throws the following error.
System.NotSupportedException: Constructing instances of generic types from Java is not supported, as the type parameters cannot be determined. occurred
Im not sure how to create a full stack trace, as I am using my phone as the test device. Program wont run on an emulator.
Code on Github: https://github.com/StormMaster12/StockApp.
Thought it would be easier to see it on there, than copy all of my code in.
Edit Code Throwing Error.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.Content.PM;
using Android.Gms.Vision.Barcodes;
using Android.Gms.Common.Apis;
using Android.Gms.Common;
using Android.Gms.Vision;
using Android.Hardware;
using Android.Support.V4.View;
using Android.Support.V4.App;
using Android.Support.V7.App;
using Android.Support.Design.Widget;
using StockApp.UI;
using Android.Util;
namespace StockApp.BarcodeReader
{
[Activity(Label = "Barcode Fragment Activity")]
class BarcodeFragmentActivity : AppCompatActivity
{
private static string tag = "Barcode-Reader";
private static int RC_HANDLE_GMS = 9001;
private static int RC_HANDLE_CAMERA_PERM = 2;
public static string AutoFocus = "AutoFocus";
public static string UseFlash = "UseFlash";
public static string BarcodeObject = "Barcode";
private CameraSourcePreview<BarcodeGraphic> mPreview;
private Android.Gms.Vision.CameraSource mCameraSource;
private GraphicOverlay<BarcodeGraphic> mGraphicOverlay;
private ScaleGestureDetector scaleGestureDetector;
private GestureDetector getsureDetector;
private View layout;
private static BarcodeFragmentActivity thisInstance;
public override View OnCreateView(View parent, string name, Context context, IAttributeSet attrs)
{
return base.OnCreateView(parent, name, context, attrs);
}
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
thisInstance = this;
SetContentView(Resource.Layout.Barcode_Capture);
//LayoutInflater inflater = LayoutInflater.From(this);
//ViewGroup viewGroup = (ViewGroup)FindViewById(Resource.Id.preview);
//View child = inflater.Inflate(Resource.Layout.layout1, viewGroup, true);
mPreview = (CameraSourcePreview<BarcodeGraphic>)FindViewById(Resource.Id.preview);
mGraphicOverlay = (GraphicOverlay<BarcodeGraphic>)FindViewById(Resource.Id.graphicOverlay);
bool autoFocus = Intent.GetBooleanExtra(AutoFocus, false);
bool useFlash = Intent.GetBooleanExtra(UseFlash, false);
int rc = (int) ActivityCompat.CheckSelfPermission(this, Manifest.Permission.Camera);
if (rc == (int) Permission.Granted)
{
createCameraSource(autoFocus, useFlash);
}
else
{
requestCameraPermission();
}
getsureDetector = new GestureDetector(this, new CaptureGestureListener());
}
private void requestCameraPermission()
{
string[] permissions = new string[] { Manifest.Permission.CallPhone };
if (ActivityCompat.ShouldShowRequestPermissionRationale(this, Manifest.Permission.Camera))
{
Snackbar.Make(layout, "Require Camera Permions To Read Barcodes", Snackbar.LengthIndefinite)
.SetAction("Ok", new Action<View> (delegate(View obj)
{
ActivityCompat.RequestPermissions(this, permissions, RC_HANDLE_CAMERA_PERM);
}
)).Show();
}
else
{
ActivityCompat.RequestPermissions(this, permissions, RC_HANDLE_CAMERA_PERM);
}
//Activity thisActivity = this;
//View.IOnClickListener listener = new View.IOnClickListener;
}
public override bool OnTouchEvent(MotionEvent e)
{
bool b = scaleGestureDetector.OnTouchEvent(e);
bool c = getsureDetector.OnTouchEvent(e);
return b || c || base.OnTouchEvent(e);
}
private void createCameraSource(bool autoFocus, bool useFlash)
{
Context context = ApplicationContext;
BarcodeDetector barcodeDetector = new BarcodeDetector.Builder(context).Build();
BarcodeTrackerFactory barcodeFactory = new BarcodeTrackerFactory(mGraphicOverlay);
barcodeDetector.SetProcessor(
new MultiProcessor.Builder(barcodeFactory).Build());
if (!barcodeDetector.IsOperational)
{
IntentFilter lowstorageFilter = new IntentFilter(Intent.ActionDeviceStorageLow);
bool hasLowStorage = RegisterReceiver(null, lowstorageFilter) != null;
if (hasLowStorage)
{
Toast.MakeText(this, "Low Storage Error", ToastLength.Long);
}
}
Android.Gms.Vision.CameraSource.Builder builder = new Android.Gms.Vision.CameraSource.Builder(base.ApplicationContext, barcodeDetector)
.SetFacing(Android.Gms.Vision.CameraFacing.Back)
.SetRequestedPreviewSize(1600, 1024)
.SetRequestedFps(15.0f)
.SetAutoFocusEnabled(true);
mCameraSource = builder.Build();
}
private void startCameraSource()
{
int code = GoogleApiAvailability.Instance.IsGooglePlayServicesAvailable(ApplicationContext);
if(code != ConnectionResult.Success)
{
Dialog dig = GoogleApiAvailability.Instance.GetErrorDialog(this, code, RC_HANDLE_GMS);
dig.Show();
}
if (mCameraSource != null)
{
try
{
mPreview.start(mCameraSource, mGraphicOverlay);
}
catch (InvalidOperationException)
{
mCameraSource.Release();
mCameraSource = null;
}
}
}
private bool OnTap(float rawX, float rawY)
{
int[] location = new int[2];
mGraphicOverlay.GetLocationOnScreen(location);
float x = (rawX - location[0]);
float y = (rawY - location[1]);
Barcode best = null;
float bestDistance = float.MaxValue;
foreach (BarcodeGraphic graphic in mGraphicOverlay.getGraphics())
{
Barcode barcode = graphic.GetBarcode();
if(barcode.BoundingBox.Contains((int)x,(int)y))
{
best = barcode;
break;
}
float dx = x - barcode.BoundingBox.CenterX();
float dy = y - barcode.BoundingBox.CenterY();
float distance = (dx * dx) + (dy * dy);
if ( distance > bestDistance)
{
best = barcode;
bestDistance = distance;
}
if (best != null)
{
Intent data = new Intent();
data.PutExtra(BarcodeObject, best);
SetResult(CommonStatusCodes.Success, data);
Finish();
return true;
}
}
return false;
}
protected override void OnResume()
{
base.OnResume();
startCameraSource();
}
protected override void OnPause()
{
base.OnPause();
if (mPreview != null)
{
mPreview.stop();
}
}
protected override void OnDestroy()
{
base.OnDestroy();
if(mPreview != null)
{
mPreview.release();
}
}
private class CaptureGestureListener : GestureDetector.SimpleOnGestureListener
{
public override bool OnSingleTapConfirmed(MotionEvent e)
{
return thisInstance.OnTap(e.RawX, e.RawY) || base.OnSingleTapConfirmed(e);
}
}
private class ScaleListener : ScaleGestureDetector.IOnScaleGestureListener
{
public IntPtr Handle => throw new NotImplementedException();
public void Dispose()
{
throw new NotImplementedException();
}
public bool OnScale(ScaleGestureDetector detector)
{
return false;
}
public bool OnScaleBegin(ScaleGestureDetector detector)
{
return true;
}
public void OnScaleEnd(ScaleGestureDetector detector)
{
}
}
}
}
Code that is being called.
CameraSourcePreview
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.Gms.Vision;
using Android.Util;
using Android.Support.Annotation;
using Android.Gms.Common.Images;
using Android.Content.Res;
using Android.Graphics;
namespace StockApp.UI
{
[Register("stockapp.stockapp.ui.CameraSourcePreview")]
class CameraSourcePreview<T> : ViewGroup where T : GraphicOverlay<T>.Graphic
{
private static string TAG = "CameraSourcePreview";
private Context mContext;
private SurfaceView mSurfaceView;
public bool mStartRequested;
private bool mSurfaceAvaialbe;
private Android.Gms.Vision.CameraSource mCameraSource;
private GraphicOverlay<T> mOverlay;
private static CameraSourcePreview<T> Instance { get; set; }
public CameraSourcePreview(Context context, IAttributeSet attrs) : base(context,attrs)
{
mContext = context;
mStartRequested = false;
mSurfaceAvaialbe = false;
SurfaceCallback instance = new SurfaceCallback();
mSurfaceView = new SurfaceView(context);
mSurfaceView.Holder.AddCallback(instance);
AddView(mSurfaceView);
}
public void start(Android.Gms.Vision.CameraSource cameraSource)
{
if (cameraSource == null)
{
stop();
}
mCameraSource = cameraSource;
if(mCameraSource != null)
{
mStartRequested = true;
startIfReady();
}
}
public void start(Android.Gms.Vision.CameraSource cameraSource, GraphicOverlay<T> graphicOverlay)
{
mOverlay = graphicOverlay;
start(cameraSource);
}
public void stop()
{
if(mCameraSource != null)
{
mCameraSource.Stop();
}
}
public void release()
{
if(mCameraSource != null)
{
mCameraSource.Release();
mCameraSource = null;
}
}
private bool isPortaitMode()
{
int orientation = (int)mContext.Resources.Configuration.Orientation;
if (orientation == (int)Android.Content.Res.Orientation.Landscape)
{
return false;
}
else if (orientation == (int)Android.Content.Res.Orientation.Portrait)
{
return true;
}
return false;
}
private void startIfReady()
{
if (mStartRequested && mSurfaceAvaialbe)
{
mCameraSource.Start(mSurfaceView.Holder);
if (mOverlay != null)
{
Android.Gms.Common.Images.Size size = mCameraSource.PreviewSize;
int min = Math.Min(size.Width, size.Height);
int max = Math.Max(size.Width, size.Width);
if(isPortaitMode())
{
mOverlay.setCameraInfo(min, max, (int)mCameraSource.CameraFacing);
}
else
{
mOverlay.setCameraInfo(max, min, (int)mCameraSource.CameraFacing);
}
mOverlay.Clear();
}
mStartRequested = false;
}
}
protected override void OnLayout(bool changed, int l, int t, int r, int b)
{
int intWidth = 320;
int intHeight = 240;
if(mCameraSource != null)
{
Android.Gms.Common.Images.Size size = mCameraSource.PreviewSize;
if(size != null)
{
intWidth = size.Width;
intHeight = size.Height;
}
}
if(isPortaitMode())
{
int tmp = intWidth;
intHeight = intWidth;
intWidth = tmp;
}
int layoutWidth = l - r;
int layoutHeight = t - b;
int childWidth = layoutWidth;
int childHeight = (int)(((float)layoutWidth / (float) intHeight)*intWidth);
if (childHeight > layoutWidth)
{
childHeight = layoutHeight;
childWidth = (int)(((float)layoutHeight / (float)intHeight) * intWidth);
}
for (int i =0 ; i < ChildCount; i++ )
{
GetChildAt(i).Layout(0, 0, childWidth, childHeight);
}
try
{
startIfReady();
}
catch (Exception e)
{
Log.Debug("Something went wrong", e.ToString());
}
}
private class SurfaceCallback : ISurfaceHolderCallback
{
public IntPtr Handle => throw new NotImplementedException();
public void Dispose()
{
}
public void SurfaceChanged(ISurfaceHolder holder, [GeneratedEnum] Format format, int width, int height)
{
}
public void SurfaceCreated(ISurfaceHolder holder)
{
Instance.mSurfaceAvaialbe = true;
try
{
Instance.startIfReady();
}
catch (Exception e)
{
Log.Debug("Something went wrong",e.ToString());
}
}
public void SurfaceDestroyed(ISurfaceHolder holder)
{
Instance.mSurfaceAvaialbe = false;
}
}
}
}
GraphicOverlay
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.Gms.Vision;
using Android.Util;
using Android.Graphics;
using Java.Util;
namespace StockApp.UI
{
[Register("stockapp.stockapp.ui.GraphicOverlay")]
class GraphicOverlay<T> : View where T: GraphicOverlay<T>.Graphic
{
public T tT ;
private Object mLock = new object();
private int mPreviewWidth { get; set; }
private float mWidthScaleFactor { get; set; } = 1.0f;
private int mPreviewHeight;
private float mHeightScaleFactor { get; set; } = 1.0f;
private int mFacing { get; set; } = (int)CameraFacing.Back;
private HashSet<T> mGraphics = new HashSet<T>();
public GraphicOverlay(Context context, IAttributeSet attrs)
: base(context, attrs)
{
}
public void Clear()
{
lock(mLock)
{
mGraphics.Clear();
}
}
public void Add(T graphic)
{
lock(mLock)
{
mGraphics.Add(graphic);
}
PostInvalidate();
}
public void Remove(T graphic)
{
lock(mLock)
{
mGraphics.Remove(graphic);
}
PostInvalidate();
}
public List<T> getGraphics()
{
lock(mLock)
{
return mGraphics.ToList();
}
}
public void setCameraInfo(int previewWidth, int previewHeight, int facing)
{
lock(mLock)
{
mPreviewHeight = previewHeight;
mPreviewWidth = previewWidth;
mFacing = facing;
}
PostInvalidate();
}
protected void onDraw(Canvas canvas)
{
base.OnDraw(canvas);
lock(mLock)
{
if(mPreviewWidth !=0 && mPreviewHeight !=0)
{
mWidthScaleFactor = (float)canvas.Width / (float)mPreviewWidth;
mHeightScaleFactor = (float)canvas.Height / (float)mPreviewHeight;
}
foreach (Graphic graphic in mGraphics)
{
graphic.Draw(canvas);
}
}
}
public abstract class Graphic
{
private GraphicOverlay<T> mOverlay;
public Graphic(GraphicOverlay<T> overlay)
{
mOverlay = overlay;
}
public abstract void Draw(Canvas canvas);
public float scaleX(float horizontal) { return horizontal * mOverlay.mWidthScaleFactor; }
public float scaleY(float vertical) { return vertical * mOverlay.mHeightScaleFactor; }
public float translateX(float x)
{
float scale = scaleX(x);
if(mOverlay.mFacing == (int)CameraFacing.Front)
{
return mOverlay.Width - scale;
}
else
{
return scale;
}
}
public float translateY(float y) { return scaleY(y); }
public void postInvalidate() { mOverlay.PostInvalidate(); }
}
}
}
I am trying to make a mobile version of a board game and for some reason I have an ArrayList where all elements conform to the last element whenever a new one is added and I canĀ“t figure out why.
(i am pretty new to Android Studio)
Below are all the classes that are concerned with adding to the list:
public class ScoreBoard {
private static final ScoreBoard ourInstance = new ScoreBoard();
public static ScoreBoard getInstance() {
return ourInstance;
}
List<Player> Players;
int nrOfPlayers;
int activePlayer;
private ScoreBoard() {
Players = new ArrayList<Player>();
}
public void addPlayer(CharSequence name) {
Player p = new Player(name);
Players.add(p);
}
public void nrOfPlayers(int number)
{
nrOfPlayers = number;
}
public boolean stop()
{
boolean stop = false;
if (nrOfPlayers <= Players.size())
{
stop = true;
}
return stop;
}
public void StartGame()
{
Random random = new Random();
random.nextInt(nrOfPlayers);
}
public CharSequence GetActivePlayerName()
{
return Players.get(activePlayer).name;
}
}
public class Player {
public CharSequence name;
public int points;
public Player(CharSequence name)
{
this.name = name;
}
}
public class PlayerName extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_player_name);
}
public void addPlayer(View view)
{
ScoreBoard SB = ScoreBoard.getInstance();
TextView nameText = (TextView)findViewById(R.id.NameText);
TextView playerText = (TextView)findViewById(R.id.PlayerText);
CharSequence name = nameText.getText();
SB.addPlayer(name);
playerText.setText("Player " + (SB.Players.size() + 1) + " enter your name");
Context context = getApplicationContext();
int duration = Toast.LENGTH_SHORT;
Toast toast = Toast.makeText(context, name + " Added", duration);
toast.show();
if(SB.stop())
{
SB.StartGame();
Intent intent = new Intent(this, TakeTurn.class);
startActivity(intent);
}
else
{
}
}
}
You've used static and final while initializing. Remove them and modify your Scorecard class as follows:
private ScoreBoard ourInstance = new ScoreBoard();
public ScoreBoard getInstance() {
return ourInstance;
}
I'm brand new to Android programming and I'm trying to create a full screen Android Wear interface with custom layouts and no cards. I'm trying to go off the sample but I can't figure out how to get around using CardFragments. My MainActivity code is essentially identical to the example, with a few names changed. Here is the code for my GridViewPagerAdaper:
public class MyGridViewPagerAdapter extends FragmentGridPagerAdapter {
private final Context mContext;
public MyGridViewPagerAdapter(Context ctx, FragmentManager fm) {
super(fm);
mContext = ctx;
}
static final int[] BG_IMAGES = new int[]{
R.drawable.bg,
};
/**
* A simple container for static data in each page
*/
private static class Page {
int titleRes;
int textRes;
int iconRes;
int cardGravity = Gravity.BOTTOM;
boolean expansionEnabled = true;
float expansionFactor = 1.0f;
int expansionDirection = CardFragment.EXPAND_DOWN;
public Page(int titleRes) {
this.titleRes = titleRes;
this.textRes = textRes;
this.iconRes = iconRes;
}
public Page(int titleRes, int textRes, int iconRes, int gravity) {
this.titleRes = titleRes;
this.textRes = textRes;
this.iconRes = iconRes;
this.cardGravity = gravity;
}
}
private final Page[][] PAGES = {
{
new Page(R.drawable.tuner),
},
{
new Page(R.drawable.metronome),
new Page(R.drawable.metroplain)
},
};
#Override
public Fragment getFragment(int row, int col) {
Page page = PAGES[row][col];
// String title = page.titleRes != 0 ? mContext.getString(page.titleRes) : null;
// String text = page.textRes != 0 ? mContext.getString(page.textRes) : null;
CardFragment fragment = CardFragment.create("", "", page.iconRes);
// Advanced settings
fragment.setCardGravity(page.cardGravity);
fragment.setExpansionEnabled(page.expansionEnabled);
fragment.setExpansionDirection(page.expansionDirection);
fragment.setExpansionFactor(page.expansionFactor);
return fragment;
}
#Override
public ImageReference getBackground(int row, int column) {
return ImageReference.forDrawable(BG_IMAGES[row % BG_IMAGES.length]);
}
#Override
public int getRowCount() {
return PAGES.length;
}
#Override
public int getColumnCount(int rowNum) {
return PAGES[rowNum].length;
}
}
What's the best way to get rid of the cards and use a custom layout? Thanks for your help.
In your adapter, give your fragments as following:
private final Activity mContext;
private final Fragment[][] mFragment;
public MyGridViewPagerAdapter(Activity ctx, FragmentManager fm, Fragment[][] fragments)
{
super(fm);
mContext = ctx;
this.mFragment = fragments;
}
then override the following methods:
#Override
public Fragment getFragment(int row, int col)
{
return mFragment[row][col];
}
#Override
public int getRowCount()
{
return mFragment.length;
}
#Override
public int getColumnCount(int rowNum)
{
return mFragment[rowNum].length;
}
then in your activity do as following:
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
final GridViewPager pager = (GridViewPager) findViewById(R.id.pager);
final Fragment[][] items = {
{
CusmtomFragment.newInstance("your","arguments"),
CusmtomFragment.newInstance()
},
{
OtherFragment.newInstance(),
AnotherFragment.newInstance(1234)
}
};
// ....
pager.setAdapter(new MyGridViewPagerAdapter(this, getFragmentManager(), items));
}
Hope it helps !
If you implement a custom wearable app you can do what you want including a custom UI.
The problems are more to Is there any way to detect if the clock is round?
Or how to start the app you n the wearable. This is done with a special service. Basically you is the dataApi for that.