import android.Manifest;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.Matrix;
import android.hardware.Camera;
import android.media.Ringtone;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
import android.text.TextPaint;
import android.util.Base64;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast; import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat; import com.google.android.cameraview.CameraView; import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Timer;
import java.util.TimerTask;
import java.util.UUID; public class Ruzhu_Index_Activity extends AppCompatActivity implements Screensaver.OnTimeOutListener, View.OnClickListener {
private ImageButton imgbtn;
private ImageButton btnMenling;
private ImageButton dasao;
private ImageButton darao;
private LinearLayout text_menpai;
private TextView text_damenpai;
private ImageButton weixin;
private Screensaver mScreensaver;
private LinearLayout line_img_menling;
private LinearLayout line_text_menling;
private LinearLayout line_text_qingwudarao;
private LinearLayout linea_yingcangrenlian;
private LinearLayout linea_menpai;
int i;
//播放铃声
private Ringtone r; //视频插件
private static final String TAG = "MainActivity";
private static final int REQUEST_CAMERA_PERMISSION = 1;
private CameraView mCameraView;
//用于在子线程中处理图片数据
private Handler mBackgroundHandler;
//后置摄像头
private int mCameraId = Camera.CameraInfo.CAMERA_FACING_BACK;
//前置摄像头
private int cameraId = Camera.CameraInfo.CAMERA_FACING_FRONT;
private static final int COMPLETED = 0;
//多线程调用
private Handler handler=new Handler(){
@SuppressLint("WrongConstant")
@Override
public void handleMessage(@NonNull Message msg) {
if (msg.what == COMPLETED) {
int num = btnMenling.getTextAlignment();
System.out.println(num);
if (num == 1) {
btnMenling.setBackground(getResources().getDrawable(R.drawable.btn1));
btnMenling.setTextAlignment(2);
} else {
btnMenling.setBackground(getResources().getDrawable(R.drawable.btn_doorbell_bell_unsel));
btnMenling.setTextAlignment(1);
}
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.ruzhuindex);
//初始化控件
init();
//按钮单击事件
btn();
//添加相机监听回调
if (mCameraView != null) {
mCameraView.addCallback(mCallback);
}
//捕获屏幕状况
mScreensaver = new Screensaver(10000); //定时5秒
mScreensaver.setOnTimeOutListener(this); //监听
mScreensaver.start(); //开始计时
//门铃点击
butn_menling();
//size字体加粗
textsizi();
//隐藏标题栏
if (getSupportActionBar() != null) {
getSupportActionBar().hide();
}
//透明状态栏
setStatusBarFullTransparent();
}
//单击事件
private void btn() {
//单击事件
imgbtn.setOnClickListener(this);
darao.setOnClickListener(this);
btnMenling.setOnClickListener(this);
dasao.setOnClickListener(this);
text_damenpai.setOnClickListener(this);
} //初始化控件
private void init() {
//相机
mCameraView =findViewById(R.id.camera);
//隐藏的菜单其他功能
darao=findViewById(R.id.darao);
line_text_qingwudarao=findViewById(R.id.line_text_qingwudarao);
dasao=findViewById(R.id.dasao);
weixin=findViewById(R.id.weixin);
//门铃
line_img_menling=findViewById(R.id.line_img_menling);
btnMenling=findViewById(R.id.btn_menlin);
line_text_menling=findViewById(R.id.line_text_menling);
//菜单
imgbtn =findViewById(R.id.imgbut);
//门牌号码
text_damenpai=findViewById(R.id.text_damenpai);
linea_menpai=findViewById(R.id.linea_menpai);
text_menpai=findViewById(R.id.text_menpai);
text_menpai=findViewById(R.id.text_menpai);
//人脸框
linea_yingcangrenlian=findViewById(R.id.linea_yingcangrenlian);
} //点击门铃事件效果
private void butn_menling(){
btnMenling.setOnClickListener(mOnClickListener);
} //拍照的点击事件
@SuppressLint("WrongConstant")
private View.OnClickListener mOnClickListener = new View.OnClickListener() {
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.btn_menlin:
//播放铃声
defaule(getApplicationContext());
//唤醒相机
if (!mCameraView.isCameraOpened()){
//启动前置摄像头
mCameraView.setFacing(cameraId);
mCameraView.start();
}
//延迟1秒拍照
new Handler().postDelayed(new Runnable(){
public void run() {
//拍照
if (mCameraView!=null){
mCameraView.takePicture();
}
}
}, 1000); text_damenpai.setVisibility(View.GONE);
text_menpai.setVisibility(View.VISIBLE);
linea_yingcangrenlian.setVisibility(View.VISIBLE);
linea_menpai.setVisibility(View.GONE);
btnMenling.setBackground(getResources().getDrawable(R.drawable.btn1));
final Timer t = new Timer();
t.schedule(new TimerTask() {
@Override
public void run() {
int num = btnMenling.getTextAlignment();
Message msg = new Message();
msg.what = COMPLETED;
handler.sendMessage(msg);
if (i>2&&num==2){
i=0;
t.cancel();
}
i++;
}
},0,1000);
break;
}
}
};
//播放铃声
private void defaule(Context context){
if (r==null){
Log.e("----初始化铃声-----",getApplicationContext()+"");
String uri = "android.resource://" + context.getPackageName() + "/" + R.raw.dingdong;
Uri no = Uri.parse(uri);
r = RingtoneManager.getRingtone(context.getApplicationContext(), no);
}
if (!r.isPlaying()){
Log.e("--------播放铃声-----" ,getApplicationContext()+"");
r.play(); }
} /**
* 动态获取摄像机权限和存储权限
*/
@SuppressLint("WrongConstant")
protected void onResume() {
super.onResume();
//检查权限,如果有权限就启动相机,没有就去请求权限
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
== PackageManager.PERMISSION_GRANTED) { } else {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA},
REQUEST_CAMERA_PERMISSION);
}
//获取存储权限
if (Build.VERSION.SDK_INT >= 23) {
if (ContextCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{android.Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
}
}
}
/**
* 关闭相机
*/
protected void onPause() {
//关闭相机,释放相机
mCameraView.stop();
Log.e("**onPause()**","释放相机");
super.onPause();
}
//运行时请求权限
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
switch (requestCode) {
case REQUEST_CAMERA_PERMISSION:
if (permissions.length != 1 || grantResults.length != 1) {
throw new RuntimeException("Error on requesting camera permission.");
}
if (grantResults[0] != PackageManager.PERMISSION_GRANTED) {
Toast.makeText(this, "grantResults[0]", Toast.LENGTH_SHORT).show();
}
break;
}
}
//在子线程保存图片
private Handler getBackgroundHandler(){
if (mBackgroundHandler==null){
HandlerThread thread=new HandlerThread("background");
thread.start();
mBackgroundHandler=new Handler(thread.getLooper());
}
return mBackgroundHandler;
}
//相机 监听回调事件
private CameraView.Callback mCallback = new CameraView.Callback() {
@Override
public void onCameraOpened(CameraView cameraView) {
Log.d(TAG, "打开相机");
} @Override
public void onCameraClosed(CameraView cameraView) {
mCameraView.stop();
Log.d(TAG, "退出相机");
} @Override
public void onPictureTaken(CameraView cameraView, final byte[] data) {
Log.d(TAG, "***onPictureTaken***" + data.length);
Toast.makeText(cameraView.getContext(), "**拍照**", Toast.LENGTH_SHORT).show();
getBackgroundHandler().post(new Runnable() {
@Override
public void run() {
//在子线程中保存图片
try {
Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
Log.d("***初始化长度****", String.valueOf(data.length)); Log.i("wechat", "压缩前图片的大小" + (bitmap.getByteCount() / 1024 / 1024)
+ "M宽度为" + bitmap.getWidth() + "高度为" + bitmap.getHeight());
               //照片文件存在手机DCIM/文件夹下
                        String fileName = "/sdcard/DCIM/" + UUID.randomUUID() + ".jpg";
FileOutputStream outputStream = new FileOutputStream(fileName);
outputStream.write(data);
//判断目录是否可用
File file = new File(fileName);//创建文件
if (!file.getParentFile().exists()) {
file.getParentFile().mkdir();//创建文件夹
}
//图片的路径
String fa = file.getAbsolutePath();
//根据生成的图片路径,重新压缩,并存入内存
compress(fa);
//删除文件
deleteSingleFile(fa);
//bitmap释放
bitmap.recycle();
bitmap = null;
} catch (Exception e) {
Toast.makeText(getApplicationContext(), "拍照失败!" + e.toString(), Toast.LENGTH_LONG).show();
Log.d("错误信息:", e.toString());
e.printStackTrace();
}
}
});
}
}; /**
* 压缩图片的方法,根据个人情况而定。需要压缩则调用该方法
* @param srcPath 根据路径读取
*/
public void compress(String srcPath) {
final String fileName = "/sdcard/DCIM/" + UUID.randomUUID() + ".jpg";
DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
float hh = dm.heightPixels;
float ww = dm.widthPixels;
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inJustDecodeBounds = true;
Bitmap bitmap = BitmapFactory.decodeFile(srcPath, opts);
opts.inJustDecodeBounds = false;
int w = opts.outWidth;
int h = opts.outHeight;
int size = 0;
if (w <= ww && h <= hh) {
size = 1;
} else {
double scale = w >= h ? w / ww : h / hh;
double log = Math.log(scale) / Math.log(2);
double logCeil = Math.ceil(log);
size = (int) Math.pow(2, logCeil);
}
opts.inSampleSize = size;
bitmap = BitmapFactory.decodeFile(srcPath, opts);
//将图片旋转90°,旋转度数为:0-360,根据实际情况进行旋转
Bitmap resizePicture = rotatePicture(bitmap, 270);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int quality = 100;
resizePicture.compress(Bitmap.CompressFormat.JPEG, quality, baos);
System.out.println(baos.toByteArray().length);
//如果还大于2M,则循环减少
while (baos.toByteArray().length > 45 * 1024) {
baos.reset();
resizePicture.compress(Bitmap.CompressFormat.JPEG, quality, baos);
quality -= 20;
System.out.println(baos.toByteArray().length);
Log.i("wechat", "压缩后图片的大小" + (resizePicture.getByteCount() / 1024 / 1024)
+ "M宽度为" + resizePicture.getWidth() + "高度为" + resizePicture.getHeight() +
" byte.lenght" + (baos.toByteArray().length) / 1024 + "KB " + "quality=" + quality);
} try {
final File file = new File(fileName);//创建文件
if (!file.getParentFile().exists()) {
file.getParentFile().mkdir();//创建文件夹
}
//将bitmap写入流中
baos.writeTo(new FileOutputStream(fileName));
final String fa = file.getAbsolutePath();
Log.d("**图片存在的路径**", fa);
//上传base64位编码时,加上.replace("+", "%2B"),否则回出现上传失败
String encodeString = fileBase64String(fa).replace("+", "%2B");
Toast.makeText(getApplicationContext(), "拍照成功,照片保存在" + fa + "文件之中!", Toast.LENGTH_LONG).show();
Log.d("**base64**", encodeString);
final String destination = "body=" + encodeString + "";
new Thread(new Runnable() {
@Override
public void run() {
String post = HttpPost.SendPost(url_link, destination);
//上传成功后删除该照片
deleteSingleFile(fa);
Log.d("**数据已发送**", post.toString());
}
}).start();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
baos.flush();
baos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/** 删除单个文件
* @param filePath$Name 要删除的文件的文件名
* @return 单个文件删除成功返回true,否则返回false
*/
private boolean deleteSingleFile(String filePath$Name) {
File file = new File(filePath$Name);
// 如果文件路径所对应的文件存在,并且是一个文件,则直接删除
if (file.exists() && file.isFile()) {
if (file.delete()) {
Log.e("--Method--", "删除单个文件" + filePath$Name + "成功!");
return true;
} else {
Log.e("--Method--", "删除单个文件" + filePath$Name + "失败!");
return false;
}
} else {
Log.e("--Method--", "删除单个文件" + filePath$Name + "不存在!");
return false;
}
}
/**
* 旋转90
* @param bitmap
* @param degree 旋转的度数
* @return
*/
public Bitmap rotatePicture(final Bitmap bitmap, final int degree) {
Matrix matrix = new Matrix();
matrix.postRotate(degree);
Bitmap resizeBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
return resizeBitmap;
}
/**
*图片转bse64
* @param path 图片的路径
* @return
*/
private String fileBase64String(String path) {
try {
FileInputStream fis = new FileInputStream(path);//转换成输入流
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int count = 0;
while ((count = fis.read(buffer)) >= 0) {
baos.write(buffer, 0, count);//读取输入流并写入输出字节流中
}
fis.close();//关闭文件输入流
String uploadBuffer = new String(Base64.encodeToString(baos.toByteArray(), Base64.NO_WRAP)); //进行Base64编码
return uploadBuffer;
} catch (Exception e) {
return null;
} }
//字体加粗
private void textsizi() {
TextView tv =findViewById(R.id.Btext);
TextPaint tp = tv.getPaint();
tp.setFakeBoldText(true);
}
//全透状态栏
protected void setStatusBarFullTransparent() {
if (Build.VERSION.SDK_INT >= 21) {//21表示5.0
Window window = getWindow();
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
window.setStatusBarColor(Color.TRANSPARENT);
} else if (Build.VERSION.SDK_INT >= 19) {//19表示4.4
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
//虚拟键盘也透明
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
}
}
@Override // 时间到就会执行此方法
public void onTimeOut(Screensaver screensaver) {
//关闭相机
mCameraView.stop();
linea_yingcangrenlian.setVisibility(View.GONE);
linea_menpai.setVisibility(View.VISIBLE);
//按钮标签初始化
imgbtn.setVisibility(View.VISIBLE);
//隐藏
darao.setVisibility(View.GONE);
dasao.setVisibility(View.GONE);
weixin.setVisibility(View.GONE);
text_menpai.setVisibility(View.GONE);
text_damenpai.setVisibility(View.VISIBLE);
} /**
* 单击事件
* @param view
*/
@SuppressLint("WrongConstant")
@Override
public void onClick(View view) {
switch (view.getId()){
case R.id.darao:
line_img_menling.setVisibility(View.GONE);
line_text_menling.setVisibility(View.GONE);
line_text_qingwudarao.setVisibility(View.VISIBLE);
int colr = darao.getTextAlignment();
if (1==colr){
darao.setBackground(getResources().getDrawable(R.drawable.btn_doorbell_dontdisturb_sel));
darao.setTextAlignment(2);
}
if (2==colr){
line_img_menling.setVisibility(View.VISIBLE);
line_text_menling.setVisibility(View.VISIBLE);
line_text_qingwudarao.setVisibility(View.GONE);
darao.setBackground(getResources().getDrawable(R.drawable.btn_doorbell_dontdisturb_unsel));
darao.setTextAlignment(1);
}
break;
case R.id.imgbut:
//菜单隐藏
imgbtn.setVisibility(View.GONE);
//请勿打扰显示-立即打扫显示-微信开门显示
darao.setVisibility(View.VISIBLE);
dasao.setVisibility(View.VISIBLE);
weixin.setVisibility(View.VISIBLE);
break;
case R.id.dasao:
Intent integer=new Intent(Ruzhu_Index_Activity.this, Dasao_Index_Activity.class);
startActivity(integer);
break;
case R.id.text_damenpai:
System.out.println(1111111);
Intent integer2=new Intent(Ruzhu_Index_Activity.this,Ganjing_Index_Activity.class);
startActivity(integer2);
break;
default:
break;
}
} @Override
protected void onDestroy() {
super.onDestroy();
if (mBackgroundHandler != null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
mBackgroundHandler.getLooper().quitSafely();
} else {
mBackgroundHandler.getLooper().quit();
}
mBackgroundHandler = null;
}
} //定时调用
class task extends TimerTask {
@Override
public void run() {
Message msg = new Message();
msg.what = COMPLETED;
handler.sendMessage(msg);
}
}
//当触摸就会执行此方法
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
mScreensaver.resetTime(); //重置时间
return super.dispatchTouchEvent(ev);
}
} 最后别忘了在配置文件加上所需的权限
<uses-permission android:name ="android.permission .MOUNT_UNMOUNT_FILESYSTEMS"/>
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.INTERNET"/>
 

Android使用com.google.android.cameraview.CameraView进行拍照的更多相关文章

  1. java.lang.VerifyError: com/google/android/gms/measurement/internal/zzw

    android studio  com.google.android.gms:play-services 运行报错:java.lang.VerifyError: com/google/android/ ...

  2. [Xamarin.Android] 如何使用Google Map V2 (转帖)

    Google Map v1已經在2013年的3月開始停止支援了,目前若要在你的Android手機上使用到Google Map,就必須要使用 到Google Map v2的版本.在Xamarin要使用G ...

  3. Android开发之Google Map

    2013-07-03 Google Map 提供三种视图: 1. 传统的矢量地图,提供行政区域.交通以及商业信息等. 2. 不同分辨率的卫星照片,与Google Earth 基本一样. 3. 地形地图 ...

  4. Google Android 6.0 权限完全解析

    注:本文只针对Google原生Android系统有效, 小米魅族等手机有自己的权限机制, 可能不适用 一.运行时权限的变化及特点 新的权限机制更好的保护了用户的隐私,Google将权限分为两类,一类是 ...

  5. linux kernel API and google android compile guide

    (1)linux kernel API website: http://docs.knobbits.org/local/linux-doc/html/regulator/index.html http ...

  6. [转]Android UI:看看Google官方自定义带旋转动画的ImageView-----RotateImageView怎么写(附 图片淡入淡出效果)

    http://blog.csdn.net/yanzi1225627/article/details/22439119 众所周知,想要让ImageView旋转的话,可以用setRotation()让其围 ...

  7. Introduction to Glide, Image Loader Library for Android, recommended by Google

    In the passed Google Developer Summit Thailand, Google introduced us an Image Loader Library for And ...

  8. 关于Google Android平台的ClockworkMod Recovery恢复模式

    lockworkMod Recovery,它也被称为Clockwork与CWM,它是装载Google Android操作系统设备的一个自定义的Recovery恢复模式,它可以使得相关Android设备 ...

  9. Re-install Flyme or Native Google Android on Meizu MX4 Ubuntu (by quqi99)

    作者:张华 发表于:2017-06-23 版权声明:可以任意转载,转载时请务必以超链接形式标明文章原始出处和作者信息及本版权声明 ( http://blog.csdn.net/quqi99 ) ## ...

随机推荐

  1. flutter 如何实现文件读写(使用篇)

    flutter文件读写可以对磁盘文件进行操作,实现某些业务场景,那么我们开始来讲下这个文件读写操作. 使用的库插件(package) dart:io(用于数据处理) path_provider (用于 ...

  2. EditPlus VC2010 and 2008 C/C++配置

    源自:http://blog.csdn.net/weiling_shen/archive/2010/03/26/5421017.aspx 对于2010跟2008差不多,只需相应的修改一下路径即可:如2 ...

  3. HDU 5510:Bazinga(暴力KMP)

    http://acm.hdu.edu.cn/showproblem.php?pid=5510 Bazinga Problem Description   Ladies and gentlemen, p ...

  4. [深度学习]TensorFlow安装

    virtualenv 可以用来建立一个专属于项目的python环境,保持一个干净的环境.只需要通过命令创建一个虚拟环境,不用的时候通过命令退出,删除.实践证明用虚拟环境能避免很多糟心的事. 下面介绍一 ...

  5. kuangbin专题 专题二 搜索进阶 哈密顿绕行世界问题 HDU - 2181

    题目链接:https://vjudge.net/problem/HDU-2181 题意:一个规则的实心十二面体,它的 20个顶点标出世界著名的20个城市,你从一个城市出发经过每个城市刚好一次后回到出发 ...

  6. docker-compose一键部署redis一主二从三哨兵模式(含密码,数据持久化)

    本篇基于centos7服务器进行部署开发 一.拉取redis镜像,使用如下命令 docker pull redis 1.查看镜像是否拉取成功,使用如下命令 docker images 显示如下则证明拉 ...

  7. ASP.NET Core系列(一): .NET Core简介及安装开发环境

    大家都知道Java是跨平台的,.NET因为不具有跨平台的特性,被越来越多的开发者诟病,之前有各种间接的跨平台的方案,比如mono.但是由于各种兼容问题,最终 .NET Core出现了,它可以让程序在W ...

  8. [NOIP2003] 传染病控制题解

    问题 F: [NOIP2003] 传染病控制 时间限制: 1 Sec  内存限制: 128 MB 题目描述 [问题背景] 近来,一种新的传染病肆虐全球.蓬莱国也发现了零星感染者,为防止该病在蓬莱国大范 ...

  9. vue自定义表单生成器,可根据json参数动态生成表单

    介绍 form-create 是一个可以通过 JSON 生成具有动态渲染.数据收集.验证和提交功能的表单生成器.并且支持生成任何 Vue 组件.结合内置17种常用表单组件和自定义组件,再复杂的表单都可 ...

  10. [USACO09OCT]Invasion of the Milkweed】乳草的侵占-C++

    Farmer John一直努力让他的草地充满鲜美多汁的而又健康的牧草.可惜天不从人愿,他在植物大战人类中败下阵来.邪恶的乳草已经在他的农场的西北部份占领了一片立足之地. 草地像往常一样,被分割成一个高 ...