blob: 56d56797cdcd0011aa65a493a4930e804894bd5a [file] [log] [blame]
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.car.bugreport;
import android.annotation.Nullable;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.media.MediaRecorder;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
/**
* A view that draws MIC icon and an animated ellipsoid. The ellipsoid animation shows the sound
* amplitude from {@link MediaRecorder}.
*
* <p>All the constant values are chosen experimentally.
*/
public class VoiceRecordingView extends View {
private static final String TAG = VoiceRecordingView.class.getSimpleName();
private static final float DROPOFF_STEP = 10f;
private static final long ANIMATION_INTERVAL_MS = 70;
private static final float RECORDER_AMPLITUDE_NORMALIZER_COEF = 16192.0f;
private final Paint mPaint;
private final BitmapDrawable mMicIconDrawable;
private float mCurrentRadius;
private MediaRecorder mRecorder;
public VoiceRecordingView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
mMicIconDrawable = (BitmapDrawable) context.getDrawable(
android.R.drawable.ic_btn_speak_now);
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setColor(Color.LTGRAY);
mPaint.setStyle(Paint.Style.FILL);
}
/** Sets MediaRecorder that will be used to animate the ellipsoid. */
public void setRecorder(@Nullable MediaRecorder recorder) {
mRecorder = recorder;
invalidate();
}
@Override
protected void onSizeChanged(int w, int h, int oldW, int oldH) {
super.onSizeChanged(w, h, oldW, oldH);
float micIconWidth = mMicIconDrawable.getBitmap().getWidth();
float micIconHeight = mMicIconDrawable.getBitmap().getHeight();
int micIconDrawableWidth = (int) (micIconWidth / micIconHeight * h);
int micIconDrawableLeft = (w - micIconDrawableWidth) / 2;
mMicIconDrawable.setBounds(
new Rect(micIconDrawableLeft, 0, micIconDrawableLeft + micIconDrawableWidth, h));
}
private void updateCurrentRadius(int width) {
final float maxRadius = width / 4;
float radius = 0;
if (mRecorder != null) {
try {
radius += maxRadius * mRecorder.getMaxAmplitude()
/ RECORDER_AMPLITUDE_NORMALIZER_COEF;
} catch (IllegalStateException e) {
Log.v(TAG, "Failed to get max amplitude from MediaRecorder");
}
}
if (radius > mCurrentRadius) {
mCurrentRadius = radius;
} else {
mCurrentRadius = Math.max(radius, mCurrentRadius - DROPOFF_STEP);
}
mCurrentRadius = Math.min(maxRadius, mCurrentRadius);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
final int width = canvas.getWidth();
final int height = canvas.getHeight();
updateCurrentRadius(width);
// Draws an ellipsoid with horizontal radius calculated from MediaRecorder's amplitude.
final int mx = width / 2;
final int my = height / 2;
canvas.drawCircle(mx, my, height / 2, mPaint);
canvas.drawCircle(mx - mCurrentRadius, my, height / 2, mPaint);
canvas.drawCircle(mx + mCurrentRadius, my, height / 2, mPaint);
canvas.drawRect(mx - mCurrentRadius, 0, mx + mCurrentRadius, height, mPaint);
if (mRecorder != null) {
postInvalidateDelayed(ANIMATION_INTERVAL_MS);
}
mMicIconDrawable.draw(canvas);
}
}