zoukankan      html  css  js  c++  java
  • Android 自定义拍照,解决图片旋转,拍照参数设置兼容问题

      今天客户提了一个需求: 需要结合摄像头将拍照的图片和自己的产品(图片)整合到一张图片上面,如下图:  
     
    20150908143828051.jpg
     
    针对这个功能需要做自定义相机,根据Camera相机类和SurfaceView类来实现自定义图形预览拍照功能。
    但在实现过程中出现几个难点:
    1.如何将自己产品图片(上图的台灯)和摄像头预览的图片结合成一张图片。
    2.拍照的图片在有些手机上面出现旋转了90度的情况(Android兼容性问题)。
    3.某些手机会出现在camera.setParameters(parameters)的调用时候出现设置失败的异常java.lang.RuntimeException: setParameters failed
     
    针对第一个问题:
        开始的考虑是在布局中SurfaceView上加一层ImageView来显示产品图片,然后通过截取View的方法截取SurfaceView和ImageView的父布局来实现,但截取view的时候发现只能截取静态的方法,对于像surfaceview之类的动态的view是不能够截取的(具体的截取方法请参考下面的源码),后来才有的是绘图的方式将预览图片的bitmap和产品图片的bitmap绘制到一张图片实现图片的合并(具体方法请参考下面源码)。
     
    针对第二个问题:
        这个显然是android手机的兼容性问题,网上也有很大类似的网友提出此类问题,但给出的解决方法大都是先通过ExifInterface类来读取bitmap的旋转角度,然后根据旋转角度旋转bitmap实现,我也用这个方法检验过,但实际上此方法并不靠谱,原因是读取bitmap的角度始终为0,即使我图片在拍照后出现的旋转了90度,也是读取不了的。后来找一篇文章:http://www.xuebuyuan.com/1223069.html 该文章介绍了ExifInterface类在某些机型的有兼容性问题,并指出了问题产生的原因,我采用,拍照完成后,强制调用setPictureDegreeZero方法(具体实现参考下面源码)来重新将图片的旋转角度设置为0,终于以次方解决了问题。终于松了口气,啊哈哈。
     
     
    针对第三个问题: 
      某些机型出现了设置拍照参数失败,是因为某些参数设置对应该机型不支持,这里我需要做到的是需要确认哪些参数有兼容性问题的,经测试发现,
    // parameters.setPreviewFrameRate(3);// 每秒3帧 每秒从摄像头里面获得3个画面, 此参数在小米2上面支持,在红米note2上面不支持,
    // parameters.setPreviewSize(PreviewWidth,PreviewHeight);// 获得摄像区域的大小
    // parameters.setPictureSize(PreviewWidth,PreviewHeight);// 获得保存图片的大小 ----这个两个参数也会有兼容性问题。
     
        目前发现这里3个参数有兼容性问题,其它若有发现在补充,同时如果网友们发现了其它参数存在兼容性问题也烦请指出,谢谢。
    针对不兼容性问题,尽量避免去设置它,
    对应setPreviewSize和setPictureSize可以通过以下方式取得合适的预览尺寸进行设置,具体方法请参考下面源代码。
    // 选择合适的预览尺寸List<Camera.Size> sizeList = parameters.getSupportedPreviewSizes();
     
     
    具体实现代码:
    1. package com.example.eclipsetest;
      
      import java.io.BufferedOutputStream;
      import java.io.File;
      import java.io.FileOutputStream;
      import java.io.IOException;
      import java.lang.reflect.Method;
      import java.util.Iterator;
      import java.util.List;
      
      import android.app.Activity;
      import android.content.Context;
      import android.graphics.Bitmap;
      import android.graphics.Bitmap.Config;
      import android.graphics.BitmapFactory;
      import android.graphics.Canvas;
      import android.graphics.Matrix;
      import android.graphics.PixelFormat;
      import android.graphics.drawable.Drawable;
      import android.hardware.Camera;
      import android.hardware.Camera.AutoFocusCallback;
      import android.hardware.Camera.Parameters;
      import android.hardware.Camera.PictureCallback;
      import android.hardware.Camera.ShutterCallback;
      import android.hardware.Camera.Size;
      import android.media.ExifInterface;
      import android.os.Build;
      import android.os.Bundle;
      import android.os.Environment;
      import android.util.DisplayMetrics;
      import android.util.Log;
      import android.view.Display;
      import android.view.Gravity;
      import android.view.SurfaceHolder;
      import android.view.SurfaceView;
      import android.view.View;
      import android.view.View.MeasureSpec;
      import android.view.View.OnClickListener;
      import android.view.WindowManager;
      import android.widget.Button;
      import android.widget.FrameLayout;
      import android.widget.ImageView;
      import android.widget.ImageView.ScaleType;
      import android.widget.Toast;
      
      /**
       * 自定义拍照,将特定图片添加到预览图片中保存起来
       * 
       * @ClassName: MyCameraDemo
       * @Description:
       * @author xiaoxiao
       * @date modify by 2015-9-8 下午2:09:16
       * 
       */
      public class MyCameraDemo extends Activity {
      	private SurfaceView surface = null;
      	private Button but = null;
      	private SurfaceHolder holder = null;
      	private Camera cam = null;
      	private boolean previewRunning = true;
      	private Button but2;
      	private ImageView iv_img;
      	private FrameLayout flay_view;
      
      	@Override
      	public void onCreate(Bundle savedInstanceState) {
      		super.onCreate(savedInstanceState);
      		super.setContentView(R.layout.main);
      		this.but = (Button) super.findViewById(R.id.but);
      		this.but2 = (Button) super.findViewById(R.id.but2);
      		this.surface = (SurfaceView) super.findViewById(R.id.surface);
      		iv_img = (ImageView) findViewById(R.id.iv_img);
      		flay_view = (FrameLayout) findViewById(R.id.flay_view);
      		this.holder = this.surface.getHolder();
      		this.holder.addCallback(new MySurfaceViewCallback());
      		this.holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
      		this.holder.setFixedSize(500, 350);
      		this.but.setOnClickListener(new OnClickListenerImpl());
      		but2.setOnClickListener(new OnClickListener() {
      
      			@Override
      			public void onClick(View v) {
      				iv_img.setVisibility(View.VISIBLE);
      				iv_img.setImageResource(R.drawable.taideng);
      			}
      		});
      	}
      
      	private class OnClickListenerImpl implements OnClickListener {
      
      		@Override
      		public void onClick(View v) {
      			if (cam != null) {
      				cam.autoFocus(new AutoFocusCallbackImpl());
      			}
      		}
      
      	}
      
      	private class MySurfaceViewCallback implements SurfaceHolder.Callback {
      
      		@Override
      		public void surfaceChanged(SurfaceHolder holder, int format, int width,
      				int height) {
      
      		}
      
      		@Override
      		public void surfaceCreated(SurfaceHolder holder) {
      			if (cam != null) {
      				cam.stopPreview();// 停掉原来摄像头的预览
      				cam.release();// 释放资源
      				cam = null;// 取消原来摄像头
      			}
      			try {
      				cam = Camera.open(0); // 取得第一个摄像头
      			} catch (Exception e) {
      				// TODO: handle exception
      				Toast.makeText(MyCameraDemo.this, "摄像头打开失败", 0).show();
      				return;
      			}
      			cam = deal2(cam);
      		}
      
      		@Override
      		public void surfaceDestroyed(SurfaceHolder holder) {
      			if (cam != null) {
      				if (MyCameraDemo.this.previewRunning) {
      					cam.stopPreview(); // 停止预览
      					MyCameraDemo.this.previewRunning = false;
      				}
      				cam.stopPreview();
      				cam.release();
      				cam = null;
      			}
      		}
      
      	}
      
      	private class AutoFocusCallbackImpl implements AutoFocusCallback {
      
      		@Override
      		public void onAutoFocus(boolean success, Camera camera) {
      			if (success) { // 成功
      				cam.takePicture(sc, pc, jpgcall);
      			}
      		}
      
      	}
      
      	private PictureCallback jpgcall = new PictureCallback() {
      
      		@Override
      		public void onPictureTaken(byte[] data, Camera camera) { // 保存图片的操作
      			Bitmap bmp = BitmapFactory.decodeByteArray(data, 0, data.length);
      			// Bitmap bmp2 = new BitmapDrawable(iv_img).getDrawable();
      			// Bitmap bmp2 = BitmapFactory.decodeResource(getResources(),
      			// R.drawable.taideng);
      			// Bitmap bmp2 = drawableToBitamp(iv_img.getDrawable());
      			String fileName = "test_" + System.currentTimeMillis() + ".jpg";
      			String filePath = Environment.getExternalStorageDirectory()
      					.toString()
      					+ File.separator
      					+ "xiao"
      					+ File.separator
      					+ fileName;
      			bmp = rotateBitmapByDegree(bmp, 90);
      
      			save(bmp, filePath, fileName);
      			bmp = loadBitmap(filePath, true);
      			setPictureDegreeZero(filePath);
      
      			Bitmap bmp2 = getSmallBitmap(MyCameraDemo.this,
      					R.drawable.taideng, dip2px(MyCameraDemo.this, 200),
      					dip2px(MyCameraDemo.this, 200));
      			Bitmap bmp3 = combineBitmap(bmp, bmp2);
      			save(bmp3, filePath, fileName);
      			cam.stopPreview();
      			cam.startPreview();
      		}
      
      	};
      
      	private ShutterCallback sc = new ShutterCallback() {
      		@Override
      		public void onShutter() {
      			// 按下快门之后进行的操作
      		}
      	};
      	private PictureCallback pc = new PictureCallback() {
      
      		@Override
      		public void onPictureTaken(byte[] data, Camera camera) {
      
      		}
      
      	};
      
      	/**
      	 * 开始考虑用剪切的方法,但是截取只适合静态界面,这里surfaceView是动态的(在不断重绘)不能剪切,后来考虑用绘图的方式将两个bitmap合在一起。
      	 * 
      	 * @param view
      	 * @return
      	 */
      	private Bitmap cropView(View view) {
      		view.measure(MeasureSpec.makeMeasureSpec(100, MeasureSpec.UNSPECIFIED),
      				MeasureSpec.makeMeasureSpec(100, MeasureSpec.UNSPECIFIED));
      		view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());
      		view.buildDrawingCache();
      		Bitmap bitmap = view.getDrawingCache();
      		return bitmap;
      	}
      
      	
      	/**
      	 * 合并两张bitmap为一张
      	 * 
      	 * @param background
      	 * @param foreground
      	 * @return Bitmap
      	 */
      	public static Bitmap combineBitmap(Bitmap background, Bitmap foreground) {
      		if (background == null) {
      			return null;
      		}
      		int bgWidth = background.getWidth();
      		int bgHeight = background.getHeight();
      		int fgWidth = foreground.getWidth();
      		int fgHeight = foreground.getHeight();
      		Bitmap newmap = Bitmap
      				.createBitmap(bgWidth, bgHeight, Config.ARGB_8888);
      		Canvas canvas = new Canvas(newmap);
      		canvas.drawBitmap(background, 0, 0, null);
      		canvas.drawBitmap(foreground, (bgWidth - fgWidth) / 2,
      				(bgHeight - fgHeight) / 2, null);
      		canvas.save(Canvas.ALL_SAVE_FLAG);
      		canvas.restore();
      		return newmap;
      	}
      
      	private void save(Bitmap bitmap, String filePath, String fileName) {
      		File file = new File(filePath);
      		if (!file.getParentFile().exists()) {
      			file.getParentFile().mkdirs(); // 创建文件夹
      		}
      		try {
      			BufferedOutputStream bos = new BufferedOutputStream(
      					new FileOutputStream(file));
      			bitmap.compress(Bitmap.CompressFormat.JPEG, 80, bos); // 向缓冲区之中压缩图片
      			bos.flush();
      			bos.close();
      			Toast.makeText(MyCameraDemo.this,
      					"拍照成功,照片已保存在" + fileName + "文件之中!", Toast.LENGTH_SHORT)
      					.show();
      		} catch (Exception e) {
      			Toast.makeText(MyCameraDemo.this, "拍照失败!", Toast.LENGTH_SHORT)
      					.show();
      		}
      	}
      
      	private Bitmap bitmap;
      
      	private Bitmap drawableToBitamp(Drawable drawable) {
      		int w = drawable.getIntrinsicWidth();
      		int h = drawable.getIntrinsicHeight();
      		System.out.println("Drawable转Bitmap");
      		Bitmap.Config config = drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888
      				: Bitmap.Config.RGB_565;
      		bitmap = Bitmap.createBitmap(w, h, config);
      		// 注意,下面三行代码要用到,否在在View或者surfaceview里的canvas.drawBitmap会看不到图
      		Canvas canvas = new Canvas(bitmap);
      		drawable.setBounds(0, 0, w, h);
      		drawable.draw(canvas);
      		return bitmap;
      	}
      
      	/**
      	 * 读取图片的旋转的角度, 某些机型此方法无效
      	 * 
      	 * @param path
      	 *            图片绝对路径
      	 * @return 图片的旋转角度
      	 */
      	private int getBitmapDegree(String path) {
      		int degree = 0;
      		try {
      			// 从指定路径下读取图片,并获取其EXIF信息
      			ExifInterface exifInterface = new ExifInterface(path);
      			// 获取图片的旋转信息
      			int orientation = exifInterface.getAttributeInt(
      					ExifInterface.TAG_ORIENTATION,
      					ExifInterface.ORIENTATION_NORMAL);
      			switch (orientation) {
      			case ExifInterface.ORIENTATION_ROTATE_90:
      				degree = 90;
      				break;
      			case ExifInterface.ORIENTATION_ROTATE_180:
      				degree = 180;
      				break;
      			case ExifInterface.ORIENTATION_ROTATE_270:
      				degree = 270;
      				break;
      			}
      		} catch (IOException e) {
      			e.printStackTrace();
      		}
      		return degree;
      	}
      
      	/**
      	 * 将图片按照某个角度进行旋转
      	 * 
      	 * @param bm
      	 *            需要旋转的图片
      	 * @param degree
      	 *            旋转角度
      	 * @return 旋转后的图片
      	 */
      	public static Bitmap rotateBitmapByDegree(Bitmap bm, int degree) {
      		Bitmap returnBm = null;
      
      		// 根据旋转角度,生成旋转矩阵
      		Matrix matrix = new Matrix();
      		matrix.postRotate(degree);
      		try {
      			// 将原始图片按照旋转矩阵进行旋转,并得到新的图片
      			returnBm = Bitmap.createBitmap(bm, 0, 0, bm.getWidth(),
      					bm.getHeight(), matrix, true);
      		} catch (OutOfMemoryError e) {
      		}
      		if (returnBm == null) {
      			returnBm = bm;
      		}
      		if (bm != returnBm) {
      			bm.recycle();
      		}
      		return returnBm;
      	}
      
      	// 控制图像的正确显示方向
      	private void setDispaly(Camera.Parameters parameters, Camera camera) {
      		if (Integer.parseInt(Build.VERSION.SDK) >= 8) {
      			setDisplayOrientation(camera, 90);
      		} else {
      			parameters.setRotation(90);
      		}
      
      	}
      
      	// 实现的图像的正确显示
      	private void setDisplayOrientation(Camera camera, int i) {
      		Method downPolymorphic;
      		try {
      			downPolymorphic = camera.getClass().getMethod(
      					"setDisplayOrientation", new Class[] { int.class });
      			if (downPolymorphic != null) {
      				downPolymorphic.invoke(camera, new Object[] { i });
      			}
      		} catch (Exception e) {
      			Log.e("Came_e", "图像出错");
      		}
      	}
      
      	private Camera deal2(Camera mCamera) {
      		// 设置camera预览的角度,因为默认图片是倾斜90度的
      		// mCamera.setDisplayOrientation(90);
      
      		int PreviewWidth = 0;
      		int PreviewHeight = 0;
      		WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);// 获取窗口的管理器
      		Display display = wm.getDefaultDisplay();// 获得窗口里面的屏幕
      		Camera.Parameters parameters = mCamera.getParameters();
      		// parameters.setFlashMode(Parameters.FLASH_MODE_TORCH); //开启闪光灯,支持
      		setDispaly(parameters, mCamera);
      		// parameters.setRotation(90);
      		// parameters.setPreviewFrameRate(3);// 每秒3帧 每秒从摄像头里面获得3个画面,
      		// 某些机型(红米note2)不支持
      		parameters.setPictureFormat(PixelFormat.JPEG);// 设置照片输出的格式
      		parameters.set("jpeg-quality", 100);// 设置照片质量
      		try {
      			// 选择合适的预览尺寸
      			List<Camera.Size> sizeList = parameters.getSupportedPreviewSizes();
      			// 如果sizeList只有一个我们也没有必要做什么了,因为就他一个别无选择
      			if (sizeList.size() > 1) {
      				Iterator<Camera.Size> itor = sizeList.iterator();
      				while (itor.hasNext()) {
      					Camera.Size cur = itor.next();
      					if (cur.width >= PreviewWidth
      							&& cur.height >= PreviewHeight) {
      						PreviewWidth = cur.width;
      						PreviewHeight = cur.height;
      						break;
      					}
      				}
      			}
      			parameters.setPreviewSize(PreviewWidth, PreviewHeight); // 获得摄像区域的大小
      			parameters.setPictureSize(PreviewWidth, PreviewHeight); // 获得保存图片的大小
      			// parameters.setPreviewSize(display.getWidth(),
      			// display.getWidth()); // 获得摄像区域的大小
      			// parameters.setPictureSize(display.getWidth(),
      			// display.getWidth());// 设置拍出来的屏幕大小
      
      		} catch (Exception e) {
      			Log.e("MyCameraDemo", e.toString());
      		}
      		try {
      			cam.setPreviewDisplay(MyCameraDemo.this.holder);
      		} catch (IOException e) {
      			// TODO Auto-generated catch block
      			e.printStackTrace();
      		}
      		mCamera.setParameters(parameters);// 把上面的设置 赋给摄像头
      		mCamera.startPreview();// 开始预览
      		mCamera.cancelAutoFocus();// 2如果要实现连续的自动对焦,这一句必须加上
      		previewRunning = true;
      		return mCamera;
      	}
      
      	/** 从给定路径加载图片 */
      	public Bitmap loadBitmap(String imgpath) {
      		return BitmapFactory.decodeFile(imgpath);
      	}
      
      	/** 从给定的路径加载图片,并指定是否自动旋转方向 */
      	public Bitmap loadBitmap(String imgpath, boolean adjustOritation) {
      		if (!adjustOritation) {
      			return loadBitmap(imgpath);
      		} else {
      			Bitmap bm = loadBitmap(imgpath);
      			int digree = 0;
      			ExifInterface exif = null;
      			try {
      				exif = new ExifInterface(imgpath);
      			} catch (IOException e) {
      				e.printStackTrace();
      				exif = null;
      			}
      			if (exif != null) {
      				// 读取图片中相机方向信息
      				// int ori = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION,
      				// ExifInterface.ORIENTATION_NORMAL);
      				int ori = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION,
      						ExifInterface.ORIENTATION_FLIP_VERTICAL);
      				// 计算旋转角度
      				switch (ori) {
      				case ExifInterface.ORIENTATION_ROTATE_90:
      					digree = 90;
      					break;
      				case ExifInterface.ORIENTATION_ROTATE_180:
      					digree = 180;
      					break;
      				case ExifInterface.ORIENTATION_ROTATE_270:
      					digree = 270;
      					break;
      				default:
      					digree = 0;
      					break;
      				}
      			}
      			if (digree != 0) {
      				// 旋转图片
      				Matrix m = new Matrix();
      				m.postRotate(digree);
      				bm = Bitmap.createBitmap(bm, 0, 0, bm.getWidth(),
      						bm.getHeight(), m, true);
      			}
      			return bm;
      		}
      	}
      
      	/**
      	 * 将图片的旋转角度置为0  ,此方法可以解决某些机型拍照后图像,出现了旋转情况
      	 * 
      	 * @Title: setPictureDegreeZero
      	 * @param path
      	 * @return void
      	 * @date 2012-12-10 上午10:54:46
      	 */
      	private void setPictureDegreeZero(String path) {
      		try {
      			ExifInterface exifInterface = new ExifInterface(path);
      			// 修正图片的旋转角度,设置其不旋转。这里也可以设置其旋转的角度,可以传值过去,
      			// 例如旋转90度,传值ExifInterface.ORIENTATION_ROTATE_90,需要将这个值转换为String类型的
      			exifInterface.setAttribute(ExifInterface.TAG_ORIENTATION, "no");
      			exifInterface.saveAttributes();
      		} catch (IOException e) {
      			// TODO Auto-generated catch block
      			e.printStackTrace();
      		}
      
      	}
      
      	/**
      	 * 根据路径获取图片并压缩返回bitmap用于显示
      	 * 
      	 * @param context
      	 * @param id
      	 * @return
      	 */
      
      	private  Bitmap getSmallBitmap(Context context, int id,int width,int height) {
      		final BitmapFactory.Options options = new BitmapFactory.Options();
      		options.inJustDecodeBounds = true;
      		BitmapFactory.decodeResource(context.getResources(), id, options);
      		// 计算 缩略图大小为原始图片大小的几分之一 inSampleSize:缩略图大小为原始图片大小的几分之一
      		options.inSampleSize = calculateInSampleSize(options, width, height);
      		options.inJustDecodeBounds = false;
      
      		return BitmapFactory.decodeResource(context.getResources(), id, options);
      	}
      	
      	/**
      	 * 计算图片的缩放值
      	 * 
      	 * @param options
      	 * @param reqWidth
      	 * @param reqHeight
      	 * @return
      	 */
      	private  int calculateInSampleSize(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) {
      			final int heightRatio = Math.round((float) height / (float) reqHeight);
      			final int widthRatio = Math.round((float) width / (float) reqWidth);
      			inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
      
      		}
      		return inSampleSize;
      
      	}
      	/**
      	 * 根据手机的分辨率从 dp 的单位 转成为 px(像素)
      	 */
      	public static int dip2px(Context context, float dpValue) {
      		final float scale = context.getResources().getDisplayMetrics().density;
      		return (int) (dpValue * scale + 0.5f);
      	}
      
      	/**
      	 * 根据手机的分辨率从 px(像素) 的单位 转成为 dp
      	 */
      	public static int px2dip(Context context, float pxValue) {
      		final float scale = context.getResources().getDisplayMetrics().density;
      		return (int) (pxValue / scale + 0.5f);
      	}
      }
      

        


     
    布局文件:
    1. <?xml version="1.0" encoding="utf-8"?>
      <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
          android:layout_width="fill_parent"
          android:layout_height="fill_parent"
          android:orientation="vertical" >
          <FrameLayout
              android:id="@+id/flay_view"
              android:layout_width="fill_parent"
              android:layout_height="fill_parent"
              android:layout_weight="1000" >
              <SurfaceView
                  android:id="@+id/surface"
                  android:layout_width="fill_parent"
                  android:layout_height="fill_parent"
                  android:layout_weight="1000" />
              <ImageView 
                  android:id="@+id/iv_img"
                  android:layout_width="200dp"
                  android:layout_height="200dp"
                  android:layout_gravity="center"
                  android:visibility="gone"
                  android:src="@drawable/taideng"
                  android:scaleType="fitCenter"/>
          </FrameLayout>
          <LinearLayout
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:layout_weight="1"
              android:orientation="horizontal" >
              <Button
                  android:id="@+id/but"
                  android:layout_width="wrap_content"
                  android:layout_height="wrap_content"
                  android:layout_weight="1"
                  android:text="照相" />
              <Button
                  android:id="@+id/but2"
                  android:layout_width="wrap_content"
                  android:layout_height="wrap_content"
                  android:layout_weight="1"
                  android:text="添加图片" />
          </LinearLayout>
      </LinearLayout>  
      

        

     
    最后不要忘了权限:
        
    1. <uses-feature android:name="android.hardware.camera" />
          <uses-feature android:name="android.hardware.camera.autofocus" />
          <uses-permission android:name="android.permission.CAMERA" />
          <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
          <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> 
     
     



  • 相关阅读:
    SP笔记:交叉实现七行并成一行
    HTML tag 学习
    操作哈希表
    Efficient bipedal robots based on passivedynamic walkers
    Pushing People Around
    ZEROMOMENT PONTTHIRTY FIVE YEARS OF ITS LIFE

    Active Learning for RealTime Motion Controllers
    Accelerometerbased User Interfaces for the Control of a Physically Simulated Character
    Dynamic Response for Motion Capture Animation
  • 原文地址:https://www.cnblogs.com/xiaoxiao-study/p/867d2ad9206c8600186c90690f1e7965.html
Copyright © 2011-2022 走看看