I am wondering if it's possible to start the Watchface Service from an activity?
I tried to start the service in the onCreate method of my activity but it does not show the Watchface:
Intent serviceIntent = new Intent(this, CustomWatchFaceService);
startService(serviceIntent);
update
Here is the code for the WatchfaceService
public class CustomWatchFaceService extends CanvasWatchFaceService {
private static final String TAG = "DigitalWatchFaceService";
private static final Typeface BOLD_TYPEFACE =
Typeface.create(Typeface.SANS_SERIF, Typeface.BOLD);
private static final Typeface NORMAL_TYPEFACE =
Typeface.create(Typeface.SANS_SERIF, Typeface.NORMAL);
private static final long NORMAL_UPDATE_RATE_MS = 500;
private static final long MUTE_UPDATE_RATE_MS = TimeUnit.MINUTES.toMillis(1);
#Override
public Engine onCreateEngine() {
return new Engine();
}
private class Engine extends CanvasWatchFaceService.Engine {
static final String COLON_STRING = ":";
static final int MUTE_ALPHA = 100;
static final int NORMAL_ALPHA = 255;
static final int MSG_UPDATE_TIME = 0;
long mInteractiveUpdateRateMs = NORMAL_UPDATE_RATE_MS;
final Handler mUpdateTimeHandler = new Handler() {
#Override
public void handleMessage(Message message) {
switch (message.what) {
case MSG_UPDATE_TIME:
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "updating time");
}
invalidate();
if (shouldTimerBeRunning()) {
long timeMs = System.currentTimeMillis();
long delayMs =
mInteractiveUpdateRateMs - (timeMs % mInteractiveUpdateRateMs);
mUpdateTimeHandler.sendEmptyMessageDelayed(MSG_UPDATE_TIME, delayMs);
}
break;
}
}
};
Paint mBackgroundPaint;
Bitmap mBackgroundBitmap;
Bitmap wifiIconOn;
Bitmap wifiIconOff;
Paint mDatePaint;
Paint mNotificationPaint;
Paint mNotificationMax;
Paint mNotificationHigh;
Paint mHourPaint;
Paint mMinutePaint;
Paint mSecondPaint;
Paint mAmPmPaint;
Paint mColonPaint;
float mColonWidth;
boolean mMute;
Calendar mCalendar;
Date mDate;
SimpleDateFormat mDayOfWeekFormat;
java.text.DateFormat mDateFormat;
boolean mShouldDrawColons;
float mXOffset;
float mYOffset;
float mLineHeight;
int mInteractiveBackgroundColor =
R.color.interactive_bg;
int mInteractiveNotificationMax =
R.color.notification_max;
int mInteractiveNotificationHigh =
R.color.notification_high;
int mInteractiveNotificationColor =
R.color.notification;
int mInteractiveHourDigitsColor =
R.color.interactive_time;
int mInteractiveMinuteDigitsColor =
R.color.interactive_time;
int mInteractiveSecondDigitsColor =
R.color.interactive_time;
boolean mLowBitAmbient;
#Override
public void onCreate(SurfaceHolder holder) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "onCreate");
}
super.onCreate(holder);
Locale locale = new Locale("de");
Locale.setDefault(locale);
Configuration config = getResources().getConfiguration();
getBaseContext().getResources().updateConfiguration(config,
getBaseContext().getResources().getDisplayMetrics());
setWatchFaceStyle(new WatchFaceStyle.Builder(CustomWatchFaceService.this)
.setCardPeekMode(WatchFaceStyle.PEEK_MODE_VARIABLE)
.setBackgroundVisibility(WatchFaceStyle.BACKGROUND_VISIBILITY_INTERRUPTIVE)
.setShowSystemUiTime(false)
.build());
Resources resources = CustomWatchFaceService.this.getResources();
mYOffset = resources.getDimension(R.dimen.digital_y_offset);
mLineHeight = resources.getDimension(R.dimen.digital_line_height);
setInteractiveColors();
// Not sure why the text color needs to be set here again ... it should be set in setDefaultColors()!
mDatePaint.setColor(getColor(R.color.digital_date));
mNotificationPaint.setColor(getColor(R.color.notification));
mNotificationMax.setColor(getColor(R.color.notification_max));
mNotificationHigh.setColor(getColor(R.color.notification_high));
mHourPaint.setColor(getColor(R.color.interactive_time));
mMinutePaint.setColor(getColor(R.color.interactive_time));
mSecondPaint.setColor(getColor(R.color.interactive_time));
mColonPaint.setColor(getColor(R.color.interactive_time));
//Images should be loaded here so they can be called during the Draw Method
wifiIconOn = BitmapFactory.decodeResource(CustomWatchFaceService.this.getResources(), R.drawable.wifi_on_small);
wifiIconOff = BitmapFactory.decodeResource(CustomWatchFaceService.this.getResources(), R.drawable.wifi_off_small);
mBackgroundBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.customcart_logo_240_alpha);
mCalendar = Calendar.getInstance();
mDate = new Date();
initFormats();
}
public void setInteractiveColors() {
mBackgroundPaint = new Paint();
mBackgroundPaint.setColor(getColor(mInteractiveBackgroundColor));
mNotificationPaint = createTextPaint(mInteractiveNotificationColor);
mNotificationMax = createTextPaint(mInteractiveNotificationMax);
mNotificationHigh = createTextPaint(mInteractiveNotificationHigh);
mDatePaint = createTextPaint(R.color.digital_date);
mHourPaint = createTextPaint(mInteractiveHourDigitsColor, BOLD_TYPEFACE);
mMinutePaint = createTextPaint(mInteractiveMinuteDigitsColor);
mSecondPaint = createTextPaint(mInteractiveSecondDigitsColor);
mColonPaint = createTextPaint(R.color.digital_colons);
}
#Override
public void onDestroy() {
mUpdateTimeHandler.removeMessages(MSG_UPDATE_TIME);
super.onDestroy();
}
private Paint createTextPaint(int defaultInteractiveColor) {
return createTextPaint(defaultInteractiveColor, NORMAL_TYPEFACE);
}
private Paint createTextPaint(int defaultInteractiveColor, Typeface typeface) {
Paint paint = new Paint();
paint.setColor(defaultInteractiveColor);
paint.setTypeface(typeface);
paint.setAntiAlias(true);
return paint;
}
#Override
public void onVisibilityChanged(boolean visible) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "onVisibilityChanged: " + visible);
}
super.onVisibilityChanged(visible);
updateTimer();
}
private void initFormats() {
mDayOfWeekFormat = new SimpleDateFormat("EEEE", Locale.getDefault());
mDayOfWeekFormat.setCalendar(mCalendar);
mDateFormat = DateFormat.getDateFormat(CustomWatchFaceService.this);
mDateFormat.setCalendar(mCalendar);
}
#Override
public void onApplyWindowInsets(WindowInsets insets) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "onApplyWindowInsets: " + (insets.isRound() ? "round" : "square"));
}
super.onApplyWindowInsets(insets);
// Load resources that have alternate values for round watches.
Resources resources = CustomWatchFaceService.this.getResources();
boolean isRound = insets.isRound();
mXOffset = resources.getDimension(isRound
? R.dimen.digital_x_offset_round : R.dimen.digital_x_offset);
float textSize = resources.getDimension(isRound
? R.dimen.digital_text_size_round : R.dimen.digital_text_size);
float notificationTextSize = resources.getDimension(isRound
? R.dimen.notification_text_size : R.dimen.notification_text_size);
mDatePaint.setTextSize(resources.getDimension(R.dimen.digital_date_text_size));
mHourPaint.setTextSize(textSize);
mMinutePaint.setTextSize(textSize);
mSecondPaint.setTextSize(textSize);
mColonPaint.setTextSize(textSize);
mNotificationPaint.setTextSize(notificationTextSize);
mColonWidth = mColonPaint.measureText(COLON_STRING);
}
#Override
public void onPropertiesChanged(Bundle properties) {
super.onPropertiesChanged(properties);
boolean burnInProtection = properties.getBoolean(PROPERTY_BURN_IN_PROTECTION, false);
mHourPaint.setTypeface(burnInProtection ? NORMAL_TYPEFACE : BOLD_TYPEFACE);
mLowBitAmbient = properties.getBoolean(PROPERTY_LOW_BIT_AMBIENT, false);
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "onPropertiesChanged: burn-in protection = " + burnInProtection
+ ", low-bit ambient = " + mLowBitAmbient);
}
}
#Override
public void onTimeTick() {
super.onTimeTick();
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "onTimeTick: ambient = " + isInAmbientMode());
}
invalidate();
}
#Override
public void onAmbientModeChanged(boolean inAmbientMode) {
super.onAmbientModeChanged(inAmbientMode);
if (!isInAmbientMode()) {
mBackgroundPaint = new Paint();
mBackgroundPaint.setColor(getColor(R.color.interactive_bg));
mDatePaint.setColor(getColor(R.color.digital_date));
mHourPaint.setColor(getColor(R.color.interactive_time));
mMinutePaint.setColor(getColor(R.color.interactive_time));
mSecondPaint.setColor(getColor(R.color.interactive_time));
mColonPaint.setColor(getColor(R.color.interactive_time));
}
else {
mBackgroundPaint = new Paint();
mBackgroundPaint.setColor(getColor(R.color.ambient_bg));
mDatePaint.setColor(getColor(R.color.digital_date));
mHourPaint.setColor(getColor(R.color.ambient_time));
mMinutePaint.setColor(getColor(R.color.ambient_time));
mSecondPaint.setColor(getColor(R.color.ambient_time));
mColonPaint.setColor(getColor(R.color.ambient_time));
}
//Log.d("XXX", "onAmbientModeChanged: " + inAmbientMode);
if (mLowBitAmbient) {
boolean antiAlias = !inAmbientMode;
mDatePaint.setAntiAlias(antiAlias);
mHourPaint.setAntiAlias(antiAlias);
mMinutePaint.setAntiAlias(antiAlias);
mSecondPaint.setAntiAlias(antiAlias);
mAmPmPaint.setAntiAlias(antiAlias);
mColonPaint.setAntiAlias(antiAlias);
}
invalidate();
// Whether the timer should be running depends on whether we're in ambient mode (as well
// as whether we're visible), so we may need to start or stop the timer.
updateTimer();
}
#Override
public void onInterruptionFilterChanged(int interruptionFilter) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "onInterruptionFilterChanged: " + interruptionFilter);
}
super.onInterruptionFilterChanged(interruptionFilter);
boolean inMuteMode = interruptionFilter == WatchFaceService.INTERRUPTION_FILTER_NONE;
// We only need to update once a minute in mute mode.
setInteractiveUpdateRateMs(inMuteMode ? MUTE_UPDATE_RATE_MS : NORMAL_UPDATE_RATE_MS);
if (mMute != inMuteMode) {
mMute = inMuteMode;
int alpha = inMuteMode ? MUTE_ALPHA : NORMAL_ALPHA;
mDatePaint.setAlpha(alpha);
mHourPaint.setAlpha(alpha);
mMinutePaint.setAlpha(alpha);
mColonPaint.setAlpha(alpha);
mAmPmPaint.setAlpha(alpha);
invalidate();
}
}
public void setInteractiveUpdateRateMs(long updateRateMs) {
if (updateRateMs == mInteractiveUpdateRateMs) {
return;
}
mInteractiveUpdateRateMs = updateRateMs;
// Stop and restart the timer so the new update rate takes effect immediately.
if (shouldTimerBeRunning()) {
updateTimer();
}
}
private String formatTwoDigitNumber(int hour) {
return String.format("%02d", hour);
}
#Override
public void onDraw(Canvas canvas, Rect bounds) {
long now = System.currentTimeMillis();
int width = bounds.width();
int height = bounds.height();
mCalendar.setTimeInMillis(now);
mDate.setTime(now);
boolean is24Hour = DateFormat.is24HourFormat(CustomWatchFaceService.this);
// Draw the background.
canvas.drawRect(0, 0, bounds.width(), bounds.height(), mBackgroundPaint);
//Draw the background Image
if (mBackgroundBitmap == null
|| mBackgroundBitmap.getWidth() != width
|| mBackgroundBitmap.getHeight() != height) {
mBackgroundBitmap = Bitmap.createScaledBitmap(mBackgroundBitmap,
width, height, true /* filter */);
}
//Log.d("XXX", "Width: "+ mBackgroundBitmap.getWidth() + "Height: "+mBackgroundBitmap.getHeight() );
if (isInAmbientMode() && (mLowBitAmbient)) {
canvas.drawColor(Color.BLACK);
} else if (isInAmbientMode()) {
canvas.drawColor(Color.BLACK);
} else {
canvas.drawBitmap(mBackgroundBitmap, 0, 0, mBackgroundPaint);
}
// Show colons for the first half of each second so the colons blink on when the time updates.
mShouldDrawColons = (System.currentTimeMillis() % 1000) < 500;
// Draw the hours.
float x = mXOffset;
String hourString;
if (is24Hour) {
hourString = formatTwoDigitNumber(mCalendar.get(Calendar.HOUR_OF_DAY));
} else {
int hour = mCalendar.get(Calendar.HOUR);
if (hour == 0) {
hour = 12;
}
hourString = String.valueOf(hour);
}
canvas.drawText(hourString, x, mYOffset, mHourPaint);
x += mHourPaint.measureText(hourString);
// In ambient and mute modes, always draw the first colon. Otherwise, draw the
// first colon for the first half of each second.
if (isInAmbientMode() || mMute || mShouldDrawColons) {
canvas.drawText(COLON_STRING, x, mYOffset, mColonPaint);
}
x += mColonWidth;
// Draw the minutes.
String minuteString = formatTwoDigitNumber(mCalendar.get(Calendar.MINUTE));
canvas.drawText(minuteString, x, mYOffset, mMinutePaint);
x += mMinutePaint.measureText(minuteString);
// In unmuted interactive mode, draw a second blinking colon followed by the seconds.
// Otherwise, if we're in 12-hour mode, draw AM/PM
if (!isInAmbientMode() && !mMute) {
if (mShouldDrawColons) {
canvas.drawText(COLON_STRING, x, mYOffset, mColonPaint);
}
x += mColonWidth;
canvas.drawText(formatTwoDigitNumber(
mCalendar.get(Calendar.SECOND)), x, mYOffset, mSecondPaint);
} else if (!is24Hour) {
x += mColonWidth;
}
// Only render the day of week and date if there is no peek card, so they do not bleed
// into each other in ambient mode.
if (getPeekCardPosition().isEmpty()) {
// Day of week
canvas.drawText(
mDayOfWeekFormat.format(mDate),
mXOffset, mYOffset + mLineHeight, mDatePaint);
// Date
canvas.drawText(
mDateFormat.format(mDate),
mXOffset, mYOffset + mLineHeight * 2, mDatePaint);
}
}
/**
* Starts the {#link #mUpdateTimeHandler} timer if it should be running and isn't currently
* or stops it if it shouldn't be running but currently is.
*/
private void updateTimer() {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "updateTimer");
}
mUpdateTimeHandler.removeMessages(MSG_UPDATE_TIME);
if (shouldTimerBeRunning()) {
mUpdateTimeHandler.sendEmptyMessage(MSG_UPDATE_TIME);
}
}
/**
* Returns whether the {#link #mUpdateTimeHandler} timer should be running. The timer should
* only run when we're visible and in interactive mode.
*/
private boolean shouldTimerBeRunning() {
return isVisible() && !isInAmbientMode();
}
}
}
Related
private static final int SENSOR_ORIENTATION_DEFAULT_DEGREES = 90;
private static final int SENSOR_ORIENTATION_INVERSE_DEGREES = 270;
private static final SparseIntArray DEFAULT_ORIENTATIONS = new SparseIntArray();
private static final SparseIntArray INVERSE_ORIENTATIONS = new SparseIntArray();
private static final long DELAY = 1000;
long timeInMilliseconds = 0L;
long timeSwapBuff = 0L;
long updatedTime = 0L;
private long startTime = 0L;
int num = 1;
List<VideoModel> videoList;
private Handler customHandler = new Handler();
private static final String TAG = "RecordVideoActivity";
private String videoName;
static {
DEFAULT_ORIENTATIONS.append(Surface.ROTATION_0, 90);
DEFAULT_ORIENTATIONS.append(Surface.ROTATION_90, 0);
DEFAULT_ORIENTATIONS.append(Surface.ROTATION_180, 270);
DEFAULT_ORIENTATIONS.append(Surface.ROTATION_270, 180);
}
static {
INVERSE_ORIENTATIONS.append(Surface.ROTATION_0, 270);
INVERSE_ORIENTATIONS.append(Surface.ROTATION_90, 180);
INVERSE_ORIENTATIONS.append(Surface.ROTATION_180, 90);
INVERSE_ORIENTATIONS.append(Surface.ROTATION_270, 0);
}
private AutoFitTextureView mTextureView;
private ImageButton mRecordButton;
private ImageView mDots;
private ImageButton mCheckPoint;
private CameraDevice mCameraDevice;
private CameraCaptureSession mPreviewSession;
private TextureView.SurfaceTextureListener mSurfaceTextureListener
= new TextureView.SurfaceTextureListener() {
#Override
public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture,
int width, int height) {
openCamera(width, height);
}
#Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture,
int width, int height) {
configureTransform(width, height);
}
#Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
return true;
}
#Override
public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {
}
};
private Size mPreviewSize;
private Size mVideoSize;
private MediaRecorder mMediaRecorder;
private boolean mIsRecordingVideo;
private HandlerThread mBackgroundThread;
private Handler mBackgroundHandler;
private Semaphore mCameraOpenCloseLock = new Semaphore(1);
private CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {
#Override
public void onOpened(#NonNull CameraDevice cameraDevice) {
mCameraDevice = cameraDevice;
startPreview();
mCameraOpenCloseLock.release();
if (null != mTextureView) {
configureTransform(mTextureView.getWidth(), mTextureView.getHeight());
}
}
#Override
public void onDisconnected(#NonNull CameraDevice cameraDevice) {
mCameraOpenCloseLock.release();
cameraDevice.close();
mCameraDevice = null;
}
#Override
public void onError(#NonNull CameraDevice cameraDevice, int error) {
mCameraOpenCloseLock.release();
cameraDevice.close();
mCameraDevice = null;
finish();
}
};
private Integer mSensorOrientation;
private String mNextVideoAbsolutePath;
private CaptureRequest.Builder mPreviewBuilder;
private CameraManager manager;
private String cameraId;
private boolean isFlashSupported;
private ImageButton flashButton;
private ImageButton switchCamera;
private ImageButton revertVideo;
public static final String CAMERA_BACK = "0";
private TextView mChronometer;
private String flashOpt;
private long lastSavedTime;
private String prepend;
private static Size chooseVideoSize(Size[] choices) {
for (Size size : choices) {
if (size.getWidth() == size.getHeight() * 4 / 3 && size.getWidth() <= 1080) {
return size;
}
}
Log.e(TAG, "Couldn't find any suitable video size");
return choices[choices.length - 1];
}
private static Size chooseOptimalSize(Size[] choices, int width, int height, Size aspectRatio) {
// Collect the supported resolutions that are at least as big as the preview Surface
List<Size> bigEnough = new ArrayList<>();
int w = aspectRatio.getWidth();
int h = aspectRatio.getHeight();
for (Size option : choices) {
if (option.getHeight() == option.getWidth() * h / w &&
option.getWidth() >= width && option.getHeight() >= height) {
bigEnough.add(option);
}
}
// Pick the smallest of those, assuming we found any
if (bigEnough.size() > 0) {
return Collections.min(bigEnough, new CompareSizesByArea());
} else {
Log.e(TAG, "Couldn't find any suitable preview size");
return choices[0];
}
}
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_camera2_video_image);
File dir = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_MOVIES) + File.separator + AppConstants.APPDIRRECORDING);
if (dir.isDirectory()) {
deleteDirectory(dir);
}
videoList = new ArrayList<>();
mTextureView = findViewById(R.id.textureView);
mRecordButton = findViewById(R.id.videoOnlineImageButton);
mRecordButton.setImageResource(R.drawable.ic_video);
mCheckPoint = findViewById(R.id.checkPoint);
mCheckPoint.setVisibility(View.GONE);
mDots = findViewById(R.id.dot);
mRecordButton.setOnClickListener(this);
flashButton = findViewById(R.id.flashVideo);
switchCamera = findViewById(R.id.switchVideo);
revertVideo = findViewById(R.id.revertVideo);
revertVideo.setVisibility(View.GONE);
mChronometer = findViewById(R.id.chronometer);
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
flashOpt = prefs.getString(getString(R.string.flash_option), getString(R.string.auto));
if (flashOpt.equals(getString(R.string.flash_off)))
flashButton.setImageResource(R.drawable.flash_auto);
else if (flashOpt.equals(getString(R.string.flash_on)))
flashButton.setImageResource(R.drawable.flash_on);
else
flashButton.setImageResource(R.drawable.flash_off);
findViewById(R.id.checkPoint).setOnClickListener(this);
findViewById(R.id.flashVideo).setOnClickListener(this);
findViewById(R.id.switchVideo).setOnClickListener(this);
findViewById(R.id.revertVideo).setOnClickListener(this);
}
#Override
public void onResume() {
super.onResume();
startBackgroundThread();
if (mTextureView.isAvailable()) {
openCamera(mTextureView.getWidth(), mTextureView.getHeight());
} else {
mTextureView.setSurfaceTextureListener(mSurfaceTextureListener);
}
if(mIsRecordingVideo)
mRecordButton.setImageResource(R.drawable.ic_video_stop);
else
mRecordButton.setImageResource(R.drawable.ic_video);
mCheckPoint.setEnabled(true);
startTime=SystemClock.uptimeMillis();
customHandler.postDelayed(updateTimerThread, 0);
}
#Override
public void onPause() {
closeCamera();
mCheckPoint.setEnabled(false);
timeSwapBuff += timeInMilliseconds;
customHandler.removeCallbacks(updateTimerThread);
stopBackgroundThread();
super.onPause();
}
private Runnable updateTimerThread = new Runnable() {
public void run() {
timeInMilliseconds = SystemClock.uptimeMillis() - startTime;
updatedTime = timeSwapBuff + timeInMilliseconds;
int secs = (int) (updatedTime / 1000);
int mins = secs / 60;
secs = secs % 60;
int hour = mins / 60;
mChronometer.setText("" + hour + ":"
+ String.format("%02d", mins) + ":"
+ String.format("%02d", secs));
customHandler.postDelayed(this, 0);
}
};
#Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.videoOnlineImageButton: {
if (mIsRecordingVideo) {
mDots.setVisibility(View.GONE);
mChronometer.setVisibility(View.GONE);
switchCamera.setVisibility(View.VISIBLE);
mCheckPoint.setVisibility(View.GONE);
stopRecordingVideo();
Intent mediaStoreUpdateIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
mediaStoreUpdateIntent.setData(Uri.fromFile(new File(mNextVideoAbsolutePath)));
sendBroadcast(mediaStoreUpdateIntent);
} else {
mCheckPoint.setVisibility(View.VISIBLE);
switchCamera.setVisibility(View.GONE);
mChronometer.setVisibility(View.VISIBLE);
mDots.setVisibility(View.VISIBLE);
startRecordingVideo();
}
break;
}
case R.id.switchVideo: {
facingCamera = !facingCamera;
closeCamera();
if (mTextureView.isAvailable()) {
openCamera(mTextureView.getWidth(), mTextureView.getHeight());
} else {
mTextureView.setSurfaceTextureListener(mSurfaceTextureListener);
}
break;
}
case R.id.flashVideo: {
if (onFlashCheck()) {
CameraCharacteristics cameraCharacteristics = null;
try {
cameraCharacteristics = manager.getCameraCharacteristics(cameraId);
} catch (CameraAccessException e) {
e.printStackTrace();
}
Boolean available = cameraCharacteristics.get(CameraCharacteristics.FLASH_INFO_AVAILABLE);
isFlashSupported = available == null ? false : available;
switchFlash();
}
break;
}
}
}
private void startBackgroundThread() {
mBackgroundThread = new HandlerThread("CameraBackground");
mBackgroundThread.start();
mBackgroundHandler = new Handler(mBackgroundThread.getLooper());
}
private void stopBackgroundThread() {
mBackgroundThread.quitSafely();
try {
mBackgroundThread.join();
mBackgroundThread = null;
mBackgroundHandler = null;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
#SuppressLint("MissingPermission")
private void openCamera(int width, int height) {
final Activity activity = this;
if (null == activity || activity.isFinishing()) {
return;
}
manager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);
try {
Log.d(TAG, "tryAcquire");
if (!mCameraOpenCloseLock.tryAcquire(2500, TimeUnit.MILLISECONDS)) {
throw new RuntimeException("Time out waiting to lock camera opening.");
}
cameraId = manager.getCameraIdList()[1];
if (facingCamera) {
cameraId = manager.getCameraIdList()[1];
flashButton.setVisibility(View.GONE);
} else {
cameraId = manager.getCameraIdList()[0];
flashButton.setVisibility(View.VISIBLE);
}
// Choose the sizes for camera preview and video recording
CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);
StreamConfigurationMap map = characteristics
.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
mSensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
if (map == null) {
throw new RuntimeException("Cannot get available preview/video sizes");
}
mVideoSize = chooseVideoSize(map.getOutputSizes(MediaRecorder.class));
mPreviewSize = chooseOptimalSize(map.getOutputSizes(SurfaceTexture.class),
width, height, mVideoSize);
int orientation = getResources().getConfiguration().orientation;
if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
mTextureView.setAspectRatio(mPreviewSize.getWidth(), mPreviewSize.getHeight());
} else {
mTextureView.setAspectRatio(mPreviewSize.getHeight(), mPreviewSize.getWidth());
}
configureTransform(width, height);
mMediaRecorder = new MediaRecorder();
manager.openCamera(cameraId, mStateCallback, null);
} catch (CameraAccessException e) {
Toast.makeText(activity, "Cannot access the camera.", Toast.LENGTH_SHORT).show();
activity.finish();
} catch (NullPointerException e) {
} catch (InterruptedException e) {
throw new RuntimeException("Interrupted while trying to lock camera opening.");
}
}
private void closeCamera() {
try {
mCameraOpenCloseLock.acquire();
closePreviewSession();
if (null != mCameraDevice) {
mCameraDevice.close();
mCameraDevice = null;
}
if (null != mMediaRecorder) {
mMediaRecorder.release();
mMediaRecorder = null;
}
} catch (InterruptedException e) {
throw new RuntimeException("Interrupted while trying to lock camera closing.");
} finally {
mCameraOpenCloseLock.release();
}
}
private void startPreview() {
if (null == mCameraDevice || !mTextureView.isAvailable() || null == mPreviewSize) {
return;
}
try {
closePreviewSession();
SurfaceTexture texture = mTextureView.getSurfaceTexture();
assert texture != null;
texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
mPreviewBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
Surface previewSurface = new Surface(texture);
mPreviewBuilder.addTarget(previewSurface);
mCameraDevice.createCaptureSession(Collections.singletonList(previewSurface),
new CameraCaptureSession.StateCallback() {
#Override
public void onConfigured(#NonNull CameraCaptureSession session) {
mPreviewSession = session;
updatePreview();
}
#Override
public void onConfigureFailed(#NonNull CameraCaptureSession session) {
Toast.makeText(RecordVideoActivity.this, "Failed", Toast.LENGTH_SHORT).show();
}
}, mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
private void updatePreview() {
if (null == mCameraDevice) {
return;
}
try {
setUpCaptureRequestBuilder(mPreviewBuilder);
HandlerThread thread = new HandlerThread("CameraPreview");
thread.start();
mPreviewSession.setRepeatingRequest(mPreviewBuilder.build(), null, mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
private void setUpCaptureRequestBuilder(CaptureRequest.Builder builder) {
if (onFlashCheck()) {
runOnUiThread(new Runnable() {
#Override
public void run() {
flashButton.setVisibility(View.VISIBLE);
}
});
if (flashOpt.equals(getString(R.string.auto)))
builder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
else if (flashOpt.equals(getString(R.string.flash_off)))
builder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF);
else
builder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_TORCH);
} else
runOnUiThread(new Runnable() {
#Override
public void run() {
flashButton.setVisibility(View.GONE);
}
});
}
private void configureTransform(int viewWidth, int viewHeight) {
if (null == mTextureView || null == mPreviewSize) {
return;
}
int rotation = getWindowManager().getDefaultDisplay().getRotation();
Matrix matrix = new Matrix();
RectF viewRect = new RectF(0, 0, viewWidth, viewHeight);
RectF bufferRect = new RectF(0, 0, mPreviewSize.getHeight(), mPreviewSize.getWidth());
float centerX = viewRect.centerX();
float centerY = viewRect.centerY();
if (Surface.ROTATION_90 == rotation || Surface.ROTATION_270 == rotation) {
bufferRect.offset(centerX - bufferRect.centerX(), centerY - bufferRect.centerY());
matrix.setRectToRect(viewRect, bufferRect, Matrix.ScaleToFit.FILL);
float scale = Math.max(
(float) viewHeight / mPreviewSize.getHeight(),
(float) viewWidth / mPreviewSize.getWidth());
matrix.postScale(scale, scale, centerX, centerY);
matrix.postRotate(90 * (rotation - 2), centerX, centerY);
}
mTextureView.setTransform(matrix);
}
private void setUpMediaRecorder() throws IOException {
mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
File file = getVideoFilePath(this);
mNextVideoAbsolutePath = file.getAbsolutePath();
videoName = file.getName();
mMediaRecorder.setOutputFile(mNextVideoAbsolutePath);
mMediaRecorder.setVideoEncodingBitRate(10000000);
mMediaRecorder.setVideoFrameRate(30);
mMediaRecorder.setVideoSize(mVideoSize.getWidth(), mVideoSize.getHeight());
mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
int rotation = getWindowManager().getDefaultDisplay().getRotation();
switch (mSensorOrientation) {
case SENSOR_ORIENTATION_DEFAULT_DEGREES:
mMediaRecorder.setOrientationHint(DEFAULT_ORIENTATIONS.get(rotation));
break;
case SENSOR_ORIENTATION_INVERSE_DEGREES:
mMediaRecorder.setOrientationHint(INVERSE_ORIENTATIONS.get(rotation));
break;
}
mMediaRecorder.prepare();
}
private File getVideoFilePath(Context context) {
File appDir = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_MOVIES) + File.separator + AppConstants.APPDIRRECORDING);
if (!appDir.isDirectory()) {
appDir.mkdirs();
}
String timestamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String prepend = "VIDEO_" + timestamp + ".mp4";
File videoFile = null;
try {
videoFile = File.createTempFile(prepend, ".mp4", appDir);
} catch (IOException e) {
e.printStackTrace();
}
return videoFile;
}
private void startRecordingVideo() {
if (null == mCameraDevice || !mTextureView.isAvailable() || null == mPreviewSize) {
return;
}
try {
closePreviewSession();
setUpMediaRecorder();
SurfaceTexture texture = mTextureView.getSurfaceTexture();
assert texture != null;
texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
mPreviewBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_RECORD);
List<Surface> surfaces = new ArrayList<>();
// Set up Surface for the camera preview
Surface previewSurface = new Surface(texture);
surfaces.add(previewSurface);
mPreviewBuilder.addTarget(previewSurface);
// Set up Surface for the MediaRecorder
Surface recorderSurface = mMediaRecorder.getSurface();
surfaces.add(recorderSurface);
mPreviewBuilder.addTarget(recorderSurface);
mCameraDevice.createCaptureSession(surfaces, new CameraCaptureSession.StateCallback() {
#Override
public void onConfigured(#NonNull final CameraCaptureSession cameraCaptureSession) {
runOnUiThread(new Runnable() {
#Override
public void run() {
mPreviewSession = cameraCaptureSession;
updatePreview();
mIsRecordingVideo = true;
startTime = SystemClock.uptimeMillis();
mChronometer.setVisibility(View.VISIBLE);
customHandler.postDelayed(updateTimerThread, 0);
mRecordButton.setImageResource(R.drawable.ic_video_stop);
mMediaRecorder.start();
mCheckPoint.setEnabled(true);
}
});
}
#Override
public void onConfigureFailed(#NonNull CameraCaptureSession cameraCaptureSession) {
Toast.makeText(RecordVideoActivity.this, "Failed", Toast.LENGTH_SHORT).show();
}
}, mBackgroundHandler);
} catch (CameraAccessException | IOException e) {
e.printStackTrace();
}
}
private void closePreviewSession() {
if (mPreviewSession != null) {
mPreviewSession.close();
mPreviewSession = null;
}
}
#SuppressLint("ResourceType")
private void stopRecordingVideo() {
mIsRecordingVideo = false;
customHandler.removeCallbacks(updateTimerThread);
mRecordButton.setImageResource(R.drawable.ic_video);
if(mMediaRecorder!=null) {
try {
mMediaRecorder.stop();
} catch (RuntimeException e) {
e.printStackTrace();
}
mMediaRecorder.reset();
}
}
static class CompareSizesByArea implements Comparator<Size> {
#Override
public int compare(Size lhs, Size rhs) {
return Long.signum((long) lhs.getWidth() * lhs.getHeight() -
(long) rhs.getWidth() * rhs.getHeight());
}
}
#Override
protected void onDestroy() {
customHandler.removeCallbacks(updateTimerThread);
}
I have implemented following coding in my app.i used camera 2 api for video recording.i feel that video streaming is stretched. mainly when i switch camera into front one.pls help me to resolve this problem
I have implemented following coding in my app.i used camera 2 api for video recording.i feel that video streaming is stretched. mainly when i switch camera into front one.pls help me to resolve this problem
Change aspect ratio values in AutoFitTextureView class or use Textureview instead of AutoFitTextureview.
Process:*****.googlemapapp, PID: 2402
java.lang.UnsatisfiedLinkError: Couldn't load rocket from loader bvt[DexPathList[[zip file "/data/data/com.google.android.gms/app_chimera/m/00000003/DynamiteModulesB_GmsCore_prod_alldpi_release.apk"],nativeLibraryDirectories=[/vendor/lib, /system/lib]]]: findLibrary returned null
at java.lang.Runtime.loadLibrary(Runtime.java:358)
at java.lang.System.loadLibrary(System.java:526)
at com.google.maps.api.android.lib6.rocket.a.onSurfaceCreated(:com.google.android.gms.DynamiteModulesB:119)
at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1501)
at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1240)
i m Getting an error when i run my mapFragment.getMapAsync(this)
i works very well for first time ...when i start again its giving error like above ...everything works well for first time ....it is like for odd it works for even application crashesh.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
context = MapsActivity.this;
setContentView(R.layout.activity_maps);
MarkerPoints = new ArrayList<>();
nextBtn = (Button) findViewById(R.id.nextBtn);
txtDistance = (TextView) findViewById(R.id.txtDistance);
txtCheckpoint = (TextView) findViewById(R.id.txtCheckpoint);
txtDistance.setText("Distance Travel : 0 Mtr");
distance = new ArrayList<Float>();
waypoints = new ArrayList<LatLng>();
Intent i = getIntent();
Places place = (Places) i.getParcelableExtra("data");
Log.d("data", place.toString());
startPoint = place.startPoint;
endPoint = place.endPoint;
waypoints=place.waypoints;
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map);
int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
if(resultCode == ConnectionResult.SUCCESS)
{
if(mapFragment != null) {
mapFragment.getMapAsync(this);
}
}else
Toast.makeText(context, "UnAvailable", Toast.LENGTH_SHORT).show();
}
//here application crashes on alternative run on mapFragment.getMapAsync(this) ,
all code works fine for first time on second time it says
java.lang.UnsatisfiedLinkError: Couldn't load rocket from loader bvt[DexPathList[[zip file "/data/data/com.google.android.gms/app_chimera/m/00000003/DynamiteModulesB_GmsCore_prod_alldpi_release.apk"],
nativeLibraryDirectories=[/vendor/lib, /system/lib]]]:
findLibrary returned null
at java.lang.Runtime.loadLibrary(Runtime.java:358)
//i initialize maps and then according to location i change panoroma image, here Fetchurl will save the path data in routes which is List<List<HashMap<String, String>>> it is Asynchronous call
#Override
public void onMapReady(GoogleMap googleMap) {
try {
mMap = googleMap;
MarkerPoints.add(startPoint);
startMarker.position(startPoint);
startMarker.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_GREEN));
m = mMap.addMarker(startMarker);
m.setTitle("You");
m.showInfoWindow();
MarkerPoints.add(endPoint);
endMarker.position(endPoint);
endMarker.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_RED));
Marker e = mMap.addMarker(endMarker);
e.setTitle("Goal");
LatLng origin = MarkerPoints.get(0);
LatLng dest = MarkerPoints.get(1);
String url = getUrl(origin, dest);
FetchUrl FetchUrl = new FetchUrl();
FetchUrl.execute(url);
//move map camera
mMap.moveCamera(CameraUpdateFactory.newLatLng(startPoint));
mMap.animateCamera(CameraUpdateFactory.zoomTo(11));
initializeSteatView();
} catch (Exception e) {
}
}`
///here i initialize streatview
` public void initializeSteatView() {
SupportStreetViewPanoramaFragment streetViewPanoramaFragment =
(SupportStreetViewPanoramaFragment)
getSupportFragmentManager().findFragmentById(R.id.mapPanaroma);
streetViewPanoramaFragment.getStreetViewPanoramaAsync(
new OnStreetViewPanoramaReadyCallback() {
#Override
public void onStreetViewPanoramaReady(final StreetViewPanorama panorama) {
panorama.setUserNavigationEnabled(false);
panorama.setPosition(startPoint);
nextBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if(!isRouteLoaded)return;
if (currentPosition == routes.get(0).size() - 1) return;
if (currentPosition == 0) {
String s1 = routes.get(0).get(currentPosition).get("lat");
String s2 = routes.get(0).get(currentPosition).get("lng");
double d1 = Double.parseDouble(s1);
double d2 = Double.parseDouble(s2);
LatLng newPosition = new LatLng(d1, d2);
mMap.moveCamera(CameraUpdateFactory.newLatLng(newPosition));
mMap.animateCamera(CameraUpdateFactory.zoomTo(17));
panorama.setPosition(newPosition);
m.setPosition(newPosition);
distance.add(totalDistance);
for (int i = 1; i < routes.get(0).size(); i++) {
d1 = Double.parseDouble(routes.get(0).get(i - 1).get("lat"));
d2 = Double.parseDouble(routes.get(0).get(i - 1).get("lng"));
LatLng start = new LatLng(d1, d2);
d1 = Double.parseDouble(routes.get(0).get(i).get("lat"));
d2 = Double.parseDouble(routes.get(0).get(i).get("lng"));
LatLng end = new LatLng(d1, d2);
totalDistance += calculateDistance(start, end);
distance.add(totalDistance);
Log.d("distance", distance.toString());
}
final Handler handler = new Handler();
final TimerTask timertask = new TimerTask() {
#Override
public void run() {
handler.post(new Runnable() {
public void run() {
distanceTravel++;
txtDistance.setText("Distance Travel : " + distanceTravel + " Mtr");
checkDistance();
}
});
}
};
Timer timer = new Timer();
timer.schedule(timertask, 0, 500);
}
}
public void checkDistance() {
if (currentPosition == routes.get(0).size() - 1) return;
checkPoint = distance.get(currentPosition + 1);
txtCheckpoint.setText("Checkpoint : " + checkPoint);
if (checkPoint < Float.parseFloat(distanceTravel + "")) {
currentPosition++;
} else {
return;
}
String s1 = routes.get(0).get(currentPosition).get("lat");
String s2 = routes.get(0).get(currentPosition).get("lng");
double d1 = Double.parseDouble(s1);
double d2 = Double.parseDouble(s2);
LatLng newPosition = new LatLng(d1, d2);
mMap.moveCamera(CameraUpdateFactory.newLatLng(newPosition));
mMap.animateCamera(CameraUpdateFactory.zoomTo(17));
panorama.setPosition(newPosition);
m.setPosition(newPosition);
}
});
panorama.setOnStreetViewPanoramaChangeListener(new StreetViewPanorama.OnStreetViewPanoramaChangeListener() {
#Override
public void onStreetViewPanoramaChange(StreetViewPanoramaLocation streetViewPanoramaLocation) {
if(!isRouteLoaded)return;
if (routes.size() > 0) {
double lat1 = Double.parseDouble(routes.get(0).get(currentPosition).get("lat"));
double lng1 = Double.parseDouble(routes.get(0).get(currentPosition).get("lng"));
double lat2 = Double.parseDouble(routes.get(0).get
(currentPosition + 1).get("lat"));
double lng2 = Double.parseDouble(routes.get(0).get
(currentPosition + 1).get("lng"));
double dLon = (lng2 - lng1);
double y = Math.sin(dLon) * Math.cos(lat2);
double x = Math.cos(lat1) * Math.sin(lat2) - Math.sin(lat1) * Math.cos(lat2) * Math.cos(dLon);
double brng = Math.toDegrees((Math.atan2(y, x)));
// brng = (360 - ((brng + 360) % 360));
long duration = 1000;
StreetViewPanoramaCamera camera =
new StreetViewPanoramaCamera.Builder()
.zoom(panorama.getPanoramaCamera().zoom)
.tilt(panorama.getPanoramaCamera().tilt)
.bearing(Float.parseFloat(brng + ""))
.build();
panorama.animateTo(camera, duration);
}
}
});
}
});
}
`
I'm working in Eclipse and using float for my variables and values. The only issue I am getting is the huge number of digits (1.563524354) after the decimal. Can I somehow limit them to one digit after the decimal like (1.5) or no digit or decimal at all simply like 1. ?
My code:
float nCurrentSpeed;
private long startTime;
private int count;
private int pointAverage;
private Float nMaxSpeed = 0F;
DecimalFormat df = new DecimalFormat("#");
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
LocationManager lm = (LocationManager) this
.getSystemService(Context.LOCATION_SERVICE);
lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this);
this.onLocationChanged(null);
}
#Override
public void onLocationChanged(Location location) {
TextView tv = (TextView) findViewById(R.id.textView1);
TextView tvd = (TextView) findViewById(R.id.textView5);
if (location == null) {
startTime = System.currentTimeMillis();
count = 0;
pointAverage = 0;
actualizeTextField();
tv.setText("0.0");
} else {
nCurrentSpeed = location.getSpeed();
tv.setText(nCurrentSpeed + "");
count += 1;
pointAverage += location.getSpeed();
actualizeTextField();
if (nMaxSpeed < nCurrentSpeed) {
nMaxSpeed = nCurrentSpeed;
}
}
tvd.setText(nMaxSpeed.toString());
}
private void actualizeTextField() {
// TODO Auto-generated method stub
TextView tf = (TextView) findViewById(R.id.textView3);
if (count > 0) {
long timeOver = System.currentTimeMillis() - startTime;
tf.setText(String.valueOf(pointAverage / (timeOver / 1000)));
} else {
tf.setText("0.0");
}
}
DecimalFormat df = new DecimalFormat("#.#");
df.format(0.91231);
returns:
0.9
If you don't want decimal places, why don't you cast it to int then?
Like this :
double d = 1.234567;
DecimalFormat df1 = new DecimalFormat("#.##"); // set your format
System.out.print(df1.format(d))
If you don't need point values, why are you using float? Check this one.
float nCurrentSpeed;
private long startTime;
private int count;
private int pointAverage;
private int nMaxSpeed = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
LocationManager lm = (LocationManager) this
.getSystemService(Context.LOCATION_SERVICE);
lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this);
this.onLocationChanged(null);
}
#Override
public void onLocationChanged(Location location) {
TextView tv = (TextView) findViewById(R.id.textView1);
TextView tvd = (TextView) findViewById(R.id.textView5);
if (location == null) {
startTime = System.currentTimeMillis();
count = 0;
pointAverage = 0;
actualizeTextField();
tv.setText("0.0");
} else {
nCurrentSpeed = location.getSpeed();
tv.setText(nCurrentSpeed + "");
count += 1;
pointAverage += location.getSpeed();
actualizeTextField();
if (nMaxSpeed < nCurrentSpeed) {
nMaxSpeed = (int)nCurrentSpeed;
}
}
tvd.setText(String.valueOf(nMaxSpeed));
}
private void actualizeTextField() {
// TODO Auto-generated method stub
TextView tf = (TextView) findViewById(R.id.textView3);
if (count > 0) {
long timeOver = System.currentTimeMillis() - startTime;
tf.setText(String.valueOf(pointAverage / (timeOver / 1000)));
} else {
tf.setText("0.0");
}
}
I am very new to blackberry development and i don't even know how to start. I already read some part of it from it's official site
http://developer.blackberry.com/devzone/files/design/bb7/UI_Guidelines_BlackBerry_Smartphones_7_1.pdf
and other so many link, but i can not post all the link as it is saying thay if you want to post more links then you must have 10 reputation and i dont have that so sorry for that,
Now my question is i want to design layout like this http://postimg.org/image/we3leycsd/
How can i design exactly this kind of layout. I am using eclipse for Blackberry development.
Please help i already tried many things but i am not able to achieve this.
Your any kind of help would be appreciated. Thank you in advance.
I'd create a custom HorizontalFieldManager with n VerticalFieldManagers inside, then override the add and delete methods. Here is something I made before, that should work for you, it adds the new fields to the shortest column.
StaggeredListView.java:
public class StaggeredListView extends HorizontalFieldManager
{
private int column_spacing = 0;
public StaggeredListView(int columns)
{
super(VERTICAL_SCROLL | VERTICAL_SCROLLBAR | NO_HORIZONTAL_SCROLL | NO_HORIZONTAL_SCROLLBAR | USE_ALL_WIDTH);
if (columns < 1)
{
throw new RuntimeException("Number of columns needs to be larger than 0.");
}
final int width = Display.getWidth() / columns;
for (int i = 0; i < columns; i++)
{
VerticalFieldManager vfm = new VerticalFieldManager(NO_VERTICAL_SCROLL | NO_VERTICAL_SCROLLBAR | NO_HORIZONTAL_SCROLL | NO_HORIZONTAL_SCROLLBAR)
{
protected void sublayout(int maxWidth, int maxHeight)
{
maxWidth = Math.min(width, getPreferredWidth());
maxHeight = Math.min(maxHeight, getPreferredHeight());
super.sublayout(width, maxHeight);
super.setExtent(width, maxHeight);
}
};
super.add(vfm);
}
}
public int getColumnCount()
{
return getFieldCount();
}
/**
* Sets the spacing between columns.
*
* <p>
* Spacing between fields is <i><b>not</b></i> set.
* </p>
*/
public void setColumnSpacing(int spacing)
{
if (spacing < 0) throw new RuntimeException("Column spacing my not be negative.");
int length = getColumnCount();
for (int i = 1; i < length; i++)
{
((VerticalFieldManager) getField(i)).setPadding(0, 0, 0, spacing);
}
column_spacing = spacing;
}
/**
* Get the value currently assigned via the {#link #setColumnSpacing(int)} method.
*
* #return
*/
public int getColumnSpacing()
{
return column_spacing;
}
/**
* Deletes all fields from each of the columns.
*/
public void clear()
{
int length = getColumnCount();
for (int i = 0; i < length; i++)
{
((VerticalFieldManager) getField(i)).deleteAll();
}
}
/**
* Delete specified field from the columns.
*
* <p>
* Does <b><i>not</i></b> rearrange fields.
* </p>
*/
public void delete(Field field)
{
int length = getColumnCount();
for (int i = 0; i < length; i++)
{
try
{
((VerticalFieldManager) getField(i)).delete(field);
break;
} catch (IllegalArgumentException e)
{
// field not in this manager
}
}
}
/**
* Adds the field to the column with the least height.
*/
public void add(Field field)
{
// find the vfm with least height
int index = 0;
int height = ((VerticalFieldManager) getField(index)).getPreferredHeight();
int length = getColumnCount();
for (int i = 1; i < length; i++)
{
int temp_height = ((VerticalFieldManager) getField(i)).getPreferredHeight();
if (temp_height < height)
{
height = temp_height;
index = i;
}
}
((VerticalFieldManager) getField(index)).add(field);
}
}
As for the item's contained in it, I'd create a field with an image and text, then paint it myself (I've had a lot of issues with focus and find it easier just to use paint).
You can use this to make a BaseButton http://developer.blackberry.com/bbos/java/documentation/tutorial_create_custom_button_1969896_11.html
BaseButton.java:
public abstract class BaseButton extends Field
{
// flags to indicate the current visual state
protected boolean _visible = true;
protected boolean _active;
protected boolean _focus;
protected boolean drawfocus = false;
private int touch_top = 0;
private int touch_right = 0;
private int touch_bottom = 0;
private int touch_left = 0;
protected boolean fire_on_click = true; // false fires on unclick
public BaseButton()
{
this(0);
}
public BaseButton(long style)
{
super((style & Field.NON_FOCUSABLE) == Field.NON_FOCUSABLE ? style : style | Field.FOCUSABLE);
}
/**
* Sets the radius around the button to trigger touch events.
* <p>
* (0,0,0,0) by default.
* </p>
*/
public void setTouchRadius(int top, int right, int bottom, int left)
{
touch_top = top;
touch_right = right;
touch_bottom = bottom;
touch_left = left;
}
protected void onFocus(int direction)
{
_focus = true;
invalidate();
super.onFocus(direction);
}
protected void onUnfocus()
{
if (_active || _focus)
{
_focus = false;
_active = false;
invalidate();
}
super.onUnfocus();
}
public void set_visible(boolean visible)
{
_visible = visible;
invalidate();
}
public boolean is_visible()
{
return _visible;
}
protected void drawFocus(Graphics g, boolean on)
{
if (drawfocus) super.drawFocus(g, on);
}
protected void layout(int width, int height)
{
setExtent(Math.min(width, getPreferredWidth()), Math.min(height, getPreferredHeight()));
}
protected boolean keyUp(int keycode, int time)
{
if (Keypad.map(Keypad.key(keycode), Keypad.status(keycode)) == Characters.ENTER)
{
_active = false;
invalidate();
return true;
}
return false;
}
protected boolean keyDown(int keycode, int time)
{
if (Keypad.map(Keypad.key(keycode), Keypad.status(keycode)) == Characters.ENTER)
{
_active = true;
invalidate();
}
return super.keyDown(keycode, time);
}
protected boolean keyChar(char character, int status, int time)
{
if (character == Characters.ENTER)
{
clickButton();
return true;
}
return super.keyChar(character, status, time);
}
protected boolean navigationClick(int status, int time)
{
if (status != 0)
{ // non-touch event
_active = true;
invalidate();
if (fire_on_click) clickButton();
}
return true;
}
protected boolean trackwheelClick(int status, int time)
{
if (status != 0)
{ // non-touch event
_active = true;
invalidate();
if (fire_on_click) clickButton();
}
return true;
}
protected boolean navigationUnclick(int status, int time)
{
if (status != 0)
{ // non-touch event
_active = false;
invalidate();
if (!fire_on_click) clickButton();
}
return true;
}
protected boolean trackwheelUnclick(int status, int time)
{
if (status != 0)
{ // non-touch event
_active = false;
invalidate();
if (!fire_on_click) clickButton();
}
return true;
}
protected boolean invokeAction(int action)
{
switch (action)
{
case ACTION_INVOKE :
{
clickButton();
return true;
}
}
return super.invokeAction(action);
}
protected boolean touchEvent(TouchEvent message)
{
boolean isOutOfBounds = touchEventOutOfBounds(message);
switch (message.getEvent())
{
case TouchEvent.CLICK :
if (!_active)
{
_active = true;
invalidate();
}
if (!isOutOfBounds)
{
if (fire_on_click) clickButton();
return true;
}
case TouchEvent.DOWN :
if (!isOutOfBounds)
{
if (!_active)
{
_active = true;
invalidate();
}
return true;
}
return false;
case TouchEvent.UNCLICK :
if (_active)
{
_active = false;
invalidate();
}
if (!isOutOfBounds)
{
if (!fire_on_click) clickButton();
return true;
}
case TouchEvent.UP :
if (_active)
{
_active = false;
invalidate();
}
default :
return false;
}
}
private boolean touchEventOutOfBounds(TouchEvent message)
{
int x = message.getX(1);
int y = message.getY(1);
return (x < 0 - touch_left || y < 0 - touch_top || x > getWidth() + touch_right || y > getHeight() + touch_bottom);
}
public void setDirty(boolean dirty)
{
}
public void setMuddy(boolean muddy)
{
}
public void clickButton()
{
if (_visible) fieldChangeNotify(0);
}
}
ImageSubtitleButton.java:
public class ImageSubtitleButton extends BaseButton
{
private static final int FOCUS_THINKNESS = 2;
String title;
Bitmap image_default;
int height;
public ImageSubtitleButton(String title, String image_default)
{
this.image_default = Bitmap.getBitmapResource(image_default);
setTitle(title);
}
public void setTitle(String title)
{
this.title = title;
height = image_default.getHeight() + getFont().getHeight() + (FOCUS_THINKNESS * 2);
updateLayout();
invalidate();
}
public int getPreferredWidth()
{
return Math.max(getFont().getAdvance(title), image_default.getWidth());
}
public int getPreferredHeight()
{
return height;
}
protected void paint(Graphics graphics)
{
int x = (getWidth() - image_default.getWidth()) / 2;
int y = 0;
graphics.drawBitmap(x, y, image_default.getWidth(), image_default.getHeight(), image_default, 0, 0);
if (_focus)
{
graphics.setColor(Color.BLUE); // your focus colour
for (int i = 0; i < FOCUS_THINKNESS; i++)
{
graphics.drawRect(x + i, y + i, image_default.getWidth() - (i * 2), image_default.getHeight() - (i * 2));
}
}
graphics.setColor(Color.BLACK);
y = image_default.getHeight();
graphics.drawText(title, x, y);
}
}
Now you can add these to your screen as follows:
StaggedListView listview = new StaggedListView(2);
ImageSubtitleButton button = new ImageSubtitleButton("test", "test.png");
listview.add(button);
add(listview);
You'll need to set the preferred width and height of the ImageSubtitleButton to keep it uniform, as in the example image you posted.
Apologies, I don't have time to create a full answer, but I personally would not use the HFM/VFM combination to do this. Instead use one Manager that provides the Grid. If you are using a late enough level OS you have GridFieldManager that does this,
GridFieldManager
but I have had mixed experiences with that Manager. So I generally use this Manager:
TableLayoutManager
I hope this gets you going.
I am writing code for my own media-controller for VideoView.
and my code is as follows
public class FMediaController extends FrameLayout {
private MediaPlayerControl mPlayer;
private Context mContext;
private View mAnchor;
private View mRoot;
private WindowManager mWindowManager;
private Window mWindow;
private View mDecor;
private ProgressBar mProgress;
private TextView mEndTime, mCurrentTime;
private boolean mShowing;
private boolean mDragging;
private static final int sDefaultTimeout = 3000;
private static final int FADE_OUT = 1;
private static final int SHOW_PROGRESS = 2;
private boolean mUseFastForward;
private boolean mFromXml;
private boolean mListenersSet;
private View.OnClickListener mNextListener, mPrevListener;
StringBuilder mFormatBuilder;
Formatter mFormatter;
private ImageButton mPauseButton;
private ImageButton mFfwdButton;
private ImageButton mRewButton;
private ImageButton mNextButton;
private ImageButton mPrevButton;
public FMediaController(Context context, AttributeSet attrs) {
super(context, attrs);
mRoot = this;
mContext = context;
mUseFastForward = true;
mFromXml = true;
}
#Override
public void onFinishInflate() {
if (mRoot != null)
initControllerView(mRoot);
}
public FMediaController(Context context, boolean useFastForward) {
super(context);
mContext = context;
mUseFastForward = useFastForward;
initFloatingWindow();
}
public FMediaController(Context context) {
super(context);
mContext = context;
mUseFastForward = true;
initFloatingWindow();
}
private void initFloatingWindow() {
mWindowManager = (WindowManager)mContext.getSystemService("window");
mWindow = PolicyManager.makeNewWindow(mContext);
mWindow.setWindowManager(mWindowManager, null, null);
mWindow.requestFeature(Window.FEATURE_NO_TITLE);
mDecor = mWindow.getDecorView();
mDecor.setOnTouchListener(mTouchListener);
mWindow.setContentView(this);
mWindow.setBackgroundDrawableResource(android.R.color.transparent);
// While the media controller is up, the volume control keys should
// affect the media stream type
mWindow.setVolumeControlStream(AudioManager.STREAM_MUSIC);
setFocusable(true);
setFocusableInTouchMode(true);
setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
requestFocus();
}
private OnTouchListener mTouchListener = new OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
if (mShowing) {
hide();
}
}
return false;
}
};
public void setMediaPlayer(MediaPlayerControl player) {
mPlayer = player;
updatePausePlay();
}
/**
* Set the view that acts as the anchor for the control view.
* This can for example be a VideoView, or your Activity's main view.
* #param view The view to which to anchor the controller when it is visible.
*/
public void setAnchorView(View view) {
mAnchor = view;
FrameLayout.LayoutParams frameParams = new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.FILL_PARENT,
ViewGroup.LayoutParams.FILL_PARENT
);
removeAllViews();
View v = makeControllerView();
addView(v, frameParams);
}
/**
* Create the view that holds the widgets that control playback.
* Derived classes can override this to create their own.
* #return The controller view.
* #hide This doesn't work as advertised
*/
protected View makeControllerView() {
LayoutInflater inflate = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mRoot = inflate.inflate(R.layout.media_controller, null);
initControllerView(mRoot);
return mRoot;
}
private void initControllerView(View v) {
mPauseButton = (ImageButton) v.findViewById(R.id.pause);
if (mPauseButton != null) {
mPauseButton.requestFocus();
mPauseButton.setOnClickListener(mPauseListener);
}
mFfwdButton = (ImageButton) v.findViewById(R.id.ffwd);
if (mFfwdButton != null) {
mFfwdButton.setOnClickListener(mFfwdListener);
if (!mFromXml) {
mFfwdButton.setVisibility(mUseFastForward ? View.VISIBLE : View.GONE);
}
}
mRewButton = (ImageButton) v.findViewById(R.id.rew);
if (mRewButton != null) {
mRewButton.setOnClickListener(mRewListener);
if (!mFromXml) {
mRewButton.setVisibility(mUseFastForward ? View.VISIBLE : View.GONE);
}
}
// By default these are hidden. They will be enabled when setPrevNextListeners() is called
mNextButton = (ImageButton) v.findViewById(R.id.next);
if (mNextButton != null && !mFromXml && !mListenersSet) {
mNextButton.setVisibility(View.GONE);
}
mPrevButton = (ImageButton) v.findViewById(R.id.prev);
if (mPrevButton != null && !mFromXml && !mListenersSet) {
mPrevButton.setVisibility(View.GONE);
}
mProgress = (ProgressBar) v.findViewById(R.id.mediacontroller_progress);
if (mProgress != null) {
if (mProgress instanceof SeekBar) {
SeekBar seeker = (SeekBar) mProgress;
seeker.setOnSeekBarChangeListener(mSeekListener);
}
mProgress.setMax(1000);
}
mEndTime = (TextView) v.findViewById(R.id.time);
mCurrentTime = (TextView) v.findViewById(R.id.time_current);
mFormatBuilder = new StringBuilder();
mFormatter = new Formatter(mFormatBuilder, Locale.getDefault());
installPrevNextListeners();
}
/**
* Show the controller on screen. It will go away
* automatically after 3 seconds of inactivity.
*/
public void show() {
show(sDefaultTimeout);
}
/**
* Show the controller on screen. It will go away
* automatically after 'timeout' milliseconds of inactivity.
* #param timeout The timeout in milliseconds. Use 0 to show
* the controller until hide() is called.
*/
public void show(int timeout) {
if (!mShowing && mAnchor != null) {
setProgress();
int [] anchorpos = new int[2];
mAnchor.getLocationOnScreen(anchorpos);
WindowManager.LayoutParams p = new WindowManager.LayoutParams();
p.gravity = Gravity.TOP;
p.width = mAnchor.getWidth();
p.height = LayoutParams.WRAP_CONTENT;
p.x = 0;
p.y = anchorpos[1] + mAnchor.getHeight() - p.height;
p.format = PixelFormat.TRANSLUCENT;
p.type = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
p.flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
p.token = null;
p.windowAnimations = 0; // android.R.style.DropDownAnimationDown;
mWindowManager.addView(mDecor, p);
mShowing = true;
}
updatePausePlay();
// cause the progress bar to be updated even if mShowing
// was already true. This happens, for example, if we're
// paused with the progress bar showing the user hits play.
mHandler.sendEmptyMessage(SHOW_PROGRESS);
Message msg = mHandler.obtainMessage(FADE_OUT);
if (timeout != 0) {
mHandler.removeMessages(FADE_OUT);
mHandler.sendMessageDelayed(msg, timeout);
}
}
public boolean isShowing() {
return mShowing;
}
/**
* Remove the controller from the screen.
*/
public void hide() {
if (mAnchor == null)
return;
if (mShowing) {
try {
mHandler.removeMessages(SHOW_PROGRESS);
mWindowManager.removeView(mDecor);
} catch (IllegalArgumentException ex) {
Log.w("MediaController", "already removed");
}
mShowing = false;
}
}
private Handler mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
int pos;
switch (msg.what) {
case FADE_OUT:
hide();
break;
case SHOW_PROGRESS:
pos = setProgress();
if (!mDragging && mShowing && mPlayer.isPlaying()) {
msg = obtainMessage(SHOW_PROGRESS);
sendMessageDelayed(msg, 1000 - (pos % 1000));
}
break;
}
}
};
private String stringForTime(int timeMs) {
int totalSeconds = timeMs / 1000;
int seconds = totalSeconds % 60;
int minutes = (totalSeconds / 60) % 60;
int hours = totalSeconds / 3600;
mFormatBuilder.setLength(0);
if (hours > 0) {
return mFormatter.format("%d:%02d:%02d", hours, minutes, seconds).toString();
} else {
return mFormatter.format("%02d:%02d", minutes, seconds).toString();
}
}
private int setProgress() {
if (mPlayer == null || mDragging) {
return 0;
}
int position = mPlayer.getCurrentPosition();
int duration = mPlayer.getDuration();
if (mProgress != null) {
if (duration > 0) {
// use long to avoid overflow
long pos = 1000L * position / duration;
mProgress.setProgress( (int) pos);
}
int percent = mPlayer.getBufferPercentage();
mProgress.setSecondaryProgress(percent * 10);
}
if (mEndTime != null)
mEndTime.setText(stringForTime(duration));
if (mCurrentTime != null)
mCurrentTime.setText(stringForTime(position));
return position;
}
#Override
public boolean onTouchEvent(MotionEvent event) {
show(sDefaultTimeout);
return true;
}
#Override
public boolean onTrackballEvent(MotionEvent ev) {
show(sDefaultTimeout);
return false;
}
#Override
public boolean dispatchKeyEvent(KeyEvent event) {
int keyCode = event.getKeyCode();
if (event.getRepeatCount() == 0 && event.isLongPress() && (
keyCode == KeyEvent.KEYCODE_HEADSETHOOK ||
keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE ||
keyCode == KeyEvent.KEYCODE_SPACE)) {
doPauseResume();
show(sDefaultTimeout);
return true;
} else if (keyCode == KeyEvent.KEYCODE_MEDIA_STOP) {
if (mPlayer.isPlaying()) {
mPlayer.pause();
updatePausePlay();
}
return true;
} else if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN ||
keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
// don't show the controls for volume adjustment
return super.dispatchKeyEvent(event);
} else if (keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_MENU) {
hide();
return true;
} else {
show(sDefaultTimeout);
}
return super.dispatchKeyEvent(event);
}
private View.OnClickListener mPauseListener = new View.OnClickListener() {
public void onClick(View v) {
doPauseResume();
show(sDefaultTimeout);
}
};
private void updatePausePlay() {
if (mRoot == null)
return;
ImageButton button = (ImageButton) mRoot.findViewById(R.id.pause);
if (button == null)
return;
if (mPlayer.isPlaying()) {
button.setImageResource(android.R.drawable.ic_media_pause);
} else {
button.setImageResource(android.R.drawable.ic_media_play);
}
}
private void doPauseResume() {
if (mPlayer.isPlaying()) {
mPlayer.pause();
} else {
mPlayer.start();
}
updatePausePlay();
}
private OnSeekBarChangeListener mSeekListener = new OnSeekBarChangeListener() {
long duration;
public void onStartTrackingTouch(SeekBar bar) {
show(3600000);
duration = mPlayer.getDuration();
}
public void onProgressChanged(SeekBar bar, int progress, boolean fromtouch) {
if (fromtouch) {
mDragging = true;
duration = mPlayer.getDuration();
long newposition = (duration * progress) / 1000L;
mPlayer.seekTo( (int) newposition);
if (mCurrentTime != null)
mCurrentTime.setText(stringForTime( (int) newposition));
}
}
public void onStopTrackingTouch(SeekBar bar) {
mDragging = false;
setProgress();
updatePausePlay();
show(sDefaultTimeout);
}
};
#Override
public void setEnabled(boolean enabled) {
if (mPauseButton != null) {
mPauseButton.setEnabled(enabled);
}
if (mFfwdButton != null) {
mFfwdButton.setEnabled(enabled);
}
if (mRewButton != null) {
mRewButton.setEnabled(enabled);
}
if (mNextButton != null) {
mNextButton.setEnabled(enabled && mNextListener != null);
}
if (mPrevButton != null) {
mPrevButton.setEnabled(enabled && mPrevListener != null);
}
if (mProgress != null) {
mProgress.setEnabled(enabled);
}
super.setEnabled(enabled);
}
private View.OnClickListener mRewListener = new View.OnClickListener() {
public void onClick(View v) {
int pos = mPlayer.getCurrentPosition();
pos -= 5000; // milliseconds
mPlayer.seekTo(pos);
setProgress();
show(sDefaultTimeout);
}
};
private View.OnClickListener mFfwdListener = new View.OnClickListener() {
public void onClick(View v) {
int pos = mPlayer.getCurrentPosition();
pos += 15000; // milliseconds
mPlayer.seekTo(pos);
setProgress();
show(sDefaultTimeout);
}
};
private void installPrevNextListeners() {
if (mNextButton != null) {
mNextButton.setOnClickListener(mNextListener);
mNextButton.setEnabled(mNextListener != null);
}
if (mPrevButton != null) {
mPrevButton.setOnClickListener(mPrevListener);
mPrevButton.setEnabled(mPrevListener != null);
}
}
public void setPrevNextListeners(View.OnClickListener next, View.OnClickListener prev) {
mNextListener = next;
mPrevListener = prev;
mListenersSet = true;
if (mRoot != null) {
installPrevNextListeners();
if (mNextButton != null && !mFromXml) {
mNextButton.setVisibility(View.VISIBLE);
}
if (mPrevButton != null && !mFromXml) {
mPrevButton.setVisibility(View.VISIBLE);
}
}
}
public interface MediaPlayerControl {
void start();
void pause();
int getDuration();
int getCurrentPosition();
void seekTo(int pos);
boolean isPlaying();
int getBufferPercentage();
};
}
and I am getting error at "Policy manager" at initfloatwindow method and I have imported import com.android.internal.policy.PolicyManager
private void initFloatingWindow() {
mWindowManager = (WindowManager)mContext.getSystemService("window");
mWindow = PolicyManager.makeNewWindow(mContext);//I got error here
mWindow.setWindowManager(mWindowManager, null, null);
mWindow.requestFeature(Window.FEATURE_NO_TITLE);
mDecor = mWindow.getDecorView();
mDecor.setOnTouchListener(mTouchListener);
mWindow.setContentView(this);
mWindow.setBackgroundDrawableResource(android.R.color.transparent);
// While the media controller is up, the volume control keys should
// affect the media stream type
mWindow.setVolumeControlStream(AudioManager.STREAM_MUSIC);
setFocusable(true);
setFocusableInTouchMode(true);
setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
requestFocus();
}
Please anyone can help me please.Thanks in advance
PolicyManager is an internal class, not in puplic API so you cannot use it.