提交 a0ab075f 编写于 作者: O openeuler-ci-bot 提交者: Gitee

!1 Initialize anbox code and optimize audio framework

Merge pull request !1 from wigman/master

要显示的变更太多。

To preserve performance only 1000 of 1000+ files are displayed.
# Defines the Chromium style for automatic reformatting.
# http://clang.llvm.org/docs/ClangFormatStyleOptions.html
BasedOnStyle: Google
# This defaults to 'Auto'. Explicitly set it for a while, so that
# 'vector<vector<int> >' in existing files gets formatted to
# 'vector<vector<int>>'. ('Auto' means that clang-format will only use
# 'int>>' if the file already contains at least one such instance.)
Standard: Cpp11
ColumnLimit: 0
1. Please check that no similar bug is already reported. Have a look on the list of open bugs at https://github.com/anbox/anbox/issues
2. Make sure you are running the latest version of Anbox before reporting an issue. Update snap to latest: `snap refresh --devmode --edge anbox`
3. Make sure you have debug logs enabled:
`sudo snap set anbox debug.enable=true`
4. Reproduce the error while debug logs enabled.
5. Run the anbox logs collection utility and attach the tar file.
`sudo /snap/bin/anbox.collect-bug-info `
6. ** Please paste the result of `anbox system-info` below:**
<details>
<summary>anbox system-info output</summary>
```
[please paste printout of `anbox system-info` here]
```
</details>
**Please describe your problem:**
**What were you expecting?:**
**Additional info:**
# Number of days of inactivity before an issue becomes stale
daysUntilStale: 120
# Number of days of inactivity before a stale issue is closed
daysUntilClose: 7
# Issues with these labels will never be considered stale
exemptLabels:
- android
- app-support
- bug
- build
- container
- distro-support
- documentation
- duplicate
- enhancement
- help wanted
- kernel
- not-snap
- question
- session manager
- sigill
- startup
- tools
- undecided
- upstream-bug
# Label to use when marking an issue as stale
staleLabel: decaying
# Comment to post when marking an issue as stale. Set to `false` to disable
markComment: >
This issue has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs. Thank you
for your contributions.
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: false
build*/
parts/
stage/
prime/
snap/.snapcraft
android-images/
*.snap
CMakeLists.txt.user
*.o.cmd
*.symvers
*.o
*.ko
*.ko.cmd
*.mod.c
*.mod.o
modules.order
.tmp_versions
.idea
debian/anbox-modules-dkms.debhelper.log
debian/anbox-modules-dkms.substvars
debian/anbox-modules-dkms/
debian/debhelper-build-stamp
debian/files
language: cpp
os: linux
sudo: required
services:
- docker
script:
- scripts/build-with-docker.sh
People contributed to Anbox in an alphabetical sorted list:
Marius Gripsgard
Ricardo Mendoza
Simon Fels
Thomas Voß
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := libprocess-cpp-minimal
LOCAL_SRC_FILES := \
external/process-cpp-minimal/src/core/posix/process.cpp \
external/process-cpp-minimal/src/core/posix/process_group.cpp \
external/process-cpp-minimal/src/core/posix/signal.cpp \
external/process-cpp-minimal/src/core/posix/signalable.cpp \
external/process-cpp-minimal/src/core/posix/standard_stream.cpp \
external/process-cpp-minimal/src/core/posix/wait.cpp \
external/process-cpp-minimal/src/core/posix/fork.cpp \
external/process-cpp-minimal/src/core/posix/exec.cpp \
external/process-cpp-minimal/src/core/posix/child_process.cpp
LOCAL_CFLAGS := \
-DANDROID \
-fexceptions
LOCAL_C_INCLUDES += \
$(LOCAL_PATH)/external/process-cpp-minimal/include
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE_CLASS := EXECUTABLES
LOCAL_MODULE := anboxd
LOCAL_INIT_RC := android/anboxd.rc
LOCAL_SRC_FILES := \
android/service/main.cpp \
android/service/daemon.cpp \
android/service/host_connector.cpp \
android/service/local_socket_connection.cpp \
android/service/message_processor.cpp \
android/service/activity_manager_interface.cpp \
android/service/android_api_skeleton.cpp \
android/service/platform_service_interface.cpp \
android/service/platform_service.cpp \
android/service/platform_api_stub.cpp \
src/anbox/common/fd.cpp \
src/anbox/common/wait_handle.cpp \
src/anbox/rpc/message_processor.cpp \
src/anbox/rpc/pending_call_cache.cpp \
src/anbox/rpc/channel.cpp \
src/anbox/protobuf/anbox_rpc.proto \
src/anbox/protobuf/anbox_bridge.proto
proto_header_dir := $(call local-generated-sources-dir)/proto/$(LOCAL_PATH)/src/anbox/protobuf
LOCAL_C_INCLUDES += \
$(proto_header_dir) \
$(LOCAL_PATH)/external/process-cpp-minimal/include \
$(LOCAL_PATH)/src \
$(LOCAL_PATH)/android/service
LOCAL_EXPORT_C_INCLUDE_DIRS += $(proto_header_dir)
LOCAL_STATIC_LIBRARIES := \
libprocess-cpp-minimal
LOCAL_SHARED_LIBRARIES := \
liblog \
libprotobuf-cpp-lite \
libsysutils \
libbinder \
libcutils \
libutils
LOCAL_CFLAGS := \
-fexceptions \
-std=c++1y
include $(BUILD_EXECUTABLE)
include $(CLEAR_VARS)
LOCAL_MODULE_RELATIVE_PATH := hw
LOCAL_SHARED_LIBRARIES := \
liblog \
lib_renderControl_enc \
libOpenglSystemCommon
LOCAL_SRC_FILES := \
android/hwcomposer/hwcomposer.cpp
LOCAL_MODULE := hwcomposer.anbox
LOCAL_CFLAGS:= -DLOG_TAG=\"hwcomposer\"
LOCAL_C_INCLUDES += \
$(LOCAL_PATH)/android/opengl/host/include/libOpenglRender \
$(LOCAL_PATH)/android/opengl/shared/OpenglCodecCommon \
$(LOCAL_PATH)/android/opengl/system/renderControl_enc \
$(LOCAL_PATH)/android/opengl/system/OpenglSystemCommon
LOCAL_MODULE_TAGS := optional
include $(BUILD_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := audio.primary.goldfish
LOCAL_MODULE_RELATIVE_PATH := hw
LOCAL_MODULE_TAGS := optional
LOCAL_SHARED_LIBRARIES := libcutils liblog
LOCAL_SRC_FILES := \
android/audio/audio_hw.cpp
LOCAL_C_INCLUDES += \
$(LOCAL_PATH)/src
LOCAL_SHARED_LIBRARIES += libdl
LOCAL_CFLAGS := -Wno-unused-parameter
include $(BUILD_SHARED_LIBRARY)
# Include the Android.mk files below will override LOCAL_PATH so we
# have to take a copy of it here.
TMP_PATH := $(LOCAL_PATH)
include $(TMP_PATH)/android/appmgr/Android.mk
include $(TMP_PATH)/android/fingerprint/Android.mk
include $(TMP_PATH)/android/power/Android.mk
include $(TMP_PATH)/android/qemu-props/Android.mk
include $(TMP_PATH)/android/qemud/Android.mk
include $(TMP_PATH)/android/sensors/Android.mk
include $(TMP_PATH)/android/opengl/Android.mk
include $(TMP_PATH)/android/gps/Android.mk
include $(TMP_PATH)/android/lights/Android.mk
include $(TMP_PATH)/android/camera/Android.mk
include $(TMP_PATH)/android/vibrator/Android.mk
project(anbox C CXX)
cmake_minimum_required(VERSION 2.8.2)
include(CTest)
include(GNUInstallDirs)
if (NOT CMAKE_BUILD_TYPE)
message(STATUS "No build type selected, default to RelWithDebInfo")
set(CMAKE_BUILD_TYPE "RelWithDebInfo")
endif()
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -pedantic -Wno-variadic-macros -Wextra -fPIC")
# By default, all symbols are visible in the library. We strip out things we don't
# want at link time, by running a version script (see unity-scopes.map and the
# setting of LINK_FLAGS below).
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=default")
set(C_AND_CXX_WARNINGS "-pedantic -Wall -Wextra")
# Some additional warnings not included by the general flags set above.
set(EXTRA_C_WARNINGS "-Wcast-align -Wcast-qual -Wformat -Wredundant-decls -Wswitch-default")
set(EXTRA_CXX_WARNINGS "-Wnon-virtual-dtor -Wold-style-cast")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${C_AND_CXX_WARNINGS}")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_C_WARNINGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 ${C_AND_CXX_WARNINGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${EXTRA_C_WARNINGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${EXTRA_CXX_WARNINGS}")
# -fno-permissive causes warnings with clang, so we only enable it for gcc
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-permissive")
endif()
string(TOLOWER "${CMAKE_BUILD_TYPE}" cmake_build_type_lower)
if ("${cmake_build_type_lower}" STREQUAL "release" OR "${cmake_build_type_lower}" STREQUAL "relwithdebinfo")
option(Werror "Treat warnings as errors" ON)
else()
option(Werror "Treat warnings as errors" OFF)
endif()
if (${Werror})
message(STATUS "Treat warnings as errors")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror")
if ("${cmake_build_type_lower}" STREQUAL "release" OR "${cmake_build_type_lower}" STREQUAL "relwithdebinfo")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-error=deprecated-declarations")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-error=deprecated-declarations")
endif()
endif()
set(CMAKE_INCLUDE_CURRENT_DIR ON)
find_package(Boost COMPONENTS filesystem log serialization system thread program_options)
find_package(PkgConfig)
find_package(Threads)
find_package(EGL REQUIRED)
find_package(GLESv2 REQUIRED)
find_package(Protobuf REQUIRED)
pkg_check_modules(SDL2 sdl2 REQUIRED)
pkg_check_modules(SDL2_IMAGE SDL2_image REQUIRED)
pkg_check_modules(DBUS dbus-1 REQUIRED)
pkg_check_modules(LXC lxc REQUIRED)
pkg_check_modules(PROPERTIES_CPP properties-cpp REQUIRED)
pkg_check_modules(LIBSYSTEMD libsystemd REQUIRED)
message(STATUS "LXC version: ${LXC_VERSION}")
if (${LXC_VERSION} VERSION_LESS 3.0)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DENABLE_LXC2_SUPPORT")
message(STATUS "Building with LXC 2.x compatibility support")
endif()
option(ENABLE_X11 "Enable X11 support" ON)
if (ENABLE_X11)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DX11_SUPPORT")
endif()
option(ENABLE_WAYLAND "Enable wayland support" ON)
if (ENABLE_WAYLAND)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DWAYLAND_SUPPORT")
endif()
option(ENABLE_MIR "Enable mir support" OFF)
if (ENABLE_MIR)
pkg_check_modules(MIRCLIENT mirclient REQUIRED)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DMIR_SUPPORT")
endif()
if (NOT BINDERFS_PATH)
set(BINDERFS_PATH "/dev/binderfs")
endif()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DEGL_NO_X11")
if((Protobuf_VERSION VERSION_GREATER "3.7") OR (Protobuf_VERSION VERSION_EQUAL "3.7"))
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DUSE_PROTOBUF_CALLBACK_HEADER")
endif()
#####################################################################
# Enable code coverage calculation with gcov/gcovr/lcov
# Usage:
# * Switch build type to coverage (use ccmake or cmake-gui)
# * Invoke make, make test, make coverage
# * Find html report in subdir coveragereport
# * Find xml report feasible for jenkins in coverage.xml
#####################################################################
IF(CMAKE_BUILD_TYPE MATCHES [cC][oO][vV][eE][rR][aA][gG][eE])
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ftest-coverage -fprofile-arcs" )
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ftest-coverage -fprofile-arcs" )
SET(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -ftest-coverage -fprofile-arcs" )
SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -ftest-coverage -fprofile-arcs" )
ENDIF(CMAKE_BUILD_TYPE MATCHES [cC][oO][vV][eE][rR][aA][gG][eE])
find_package(GMock)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -fPIC")
if (NOT ANBOX_VERSION)
exec_program("git" ${CMAKE_SOURCE_DIR} ARGS "rev-parse --short HEAD" OUTPUT_VARIABLE GIT_COMMIT_HASH)
set(ANBOX_VERSION "local-${GIT_COMMIT_HASH}")
endif()
if (ANBOX_VERSION_SUFFIX)
set(ANBOX_VERSION "${ANBOX_VERSION}-${ANBOX_VERSION_SUFFIX}")
endif()
set(ANBOX_RESOURCE_DIR "${CMAKE_INSTALL_DATADIR}/anbox")
set(ANBOX_RESOURCE_DIR_FULL "${CMAKE_INSTALL_FULL_DATADIR}/anbox")
set(ANBOX_STATEDIR_FULL "${CMAKE_INSTALL_FULL_LOCALSTATEDIR}/lib/anbox")
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/src/anbox/build/config.h.in
${CMAKE_CURRENT_SOURCE_DIR}/src/anbox/build/config.h)
add_subdirectory(external)
add_subdirectory(src)
add_subdirectory(tests)
add_subdirectory(android)
if (NOT "${HOST_CMAKE_C_COMPILER}" STREQUAL "")
message(STATUS "Host C compiler: ${HOST_CMAKE_C_COMPILER}")
message(STATUS "Host C compiler: ${HOST_CMAKE_CXX_COMPILER}")
endif()
option(SNAP_CONFINEMENT "Enable snap confinement support" OFF)
if (SNAP_CONFINEMENT)
message(STATUS "Building with support for snap confinement")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DENABLE_SNAP_CONFINEMENT")
endif()
install(FILES data/ui/loading-screen.png DESTINATION ${ANBOX_RESOURCE_DIR}/ui)
# uninstall target
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake"
IMMEDIATE @ONLY)
add_custom_target(uninstall "${CMAKE_COMMAND}"
-P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake")
此差异已折叠。
# anbox
#### Description
A free and open-source compatibility layer that aims to allow mobile applications and mobile games developed for Android to run on GNU/Linux distributions
#### Software Architecture
Software architecture description
#### Installation
1. xxxx
2. xxxx
3. xxxx
#### Instructions
1. xxxx
2. xxxx
3. xxxx
#### Contribution
1. Fork the repository
2. Create Feat_xxx branch
3. Commit your code
4. Create Pull Request
#### Gitee Feature
1. You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md
2. Gitee blog [blog.gitee.com](https://blog.gitee.com)
3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore)
4. The most valuable open source project [GVP](https://gitee.com/gvp)
5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help)
6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)
# anbox
[![Snap Status](https://build.snapcraft.io/badge/anbox/anbox.svg)](https://build.snapcraft.io/user/anbox/anbox)
[![Build Status](https://travis-ci.org/anbox/anbox.svg?branch=master)](https://travis-ci.org/anbox/anbox)
#### 介绍
A free and open-source compatibility layer that aims to allow mobile applications and mobile games developed for Android to run on GNU/Linux distributions
# Anbox
#### 软件架构
软件架构说明
Anbox is a container-based approach to boot a full Android system on a
regular GNU/Linux system like Ubuntu. In other words: Anbox will let
you run Android on your Linux system without the slowness of
virtualization.
## Overview
#### 安装教程
Anbox uses Linux namespaces (user, pid, uts, net, mount, ipc) to run a
full Android system in a container and provide Android applications on
any GNU/Linux-based platform.
1. xxxx
2. xxxx
3. xxxx
The Android inside the container has no direct access to any hardware.
All hardware access is going through the anbox daemon on the host. We're
reusing what Android implemented within the QEMU-based emulator for OpenGL
ES accelerated rendering. The Android system inside the container uses
different pipes to communicate with the host system and sends all hardware
access commands through these.
#### 使用说明
For more details have a look at the following documentation pages:
1. xxxx
2. xxxx
3. xxxx
* [Android Hardware OpenGL ES emulation design overview](https://android.googlesource.com/platform/external/qemu/+/emu-master-dev/android/android-emugl/DESIGN)
* [Android QEMU fast pipes](https://android.googlesource.com/platform/external/qemu/+/emu-master-dev/android/docs/ANDROID-QEMU-PIPE.TXT)
* [The Android "qemud" multiplexing daemon](https://android.googlesource.com/platform/external/qemu/+/emu-master-dev/android/docs/ANDROID-QEMUD.TXT)
* [Android qemud services](https://android.googlesource.com/platform/external/qemu/+/emu-master-dev/android/docs/ANDROID-QEMUD-SERVICES.TXT)
#### 参与贡献
Anbox is currently suited for the desktop use case but can be used on
mobile operating systems like Ubuntu Touch, Sailfish OS or Lune OS too.
However as the mapping of Android applications is currently desktop specific
this needs additional work to supported stacked window user interfaces too.
1. Fork 本仓库
2. 新建 Feat_xxx 分支
3. 提交代码
4. 新建 Pull Request
The Android runtime environment ships with a minimal customized Android system
image based on the [Android Open Source Project](https://source.android.com/).
The used image is currently based on Android 7.1.1
## Installation
#### 码云特技
See our [installation instructions](docs/install.md) for details.
1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md
2. 码云官方博客 [blog.gitee.com](https://blog.gitee.com)
3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解码云上的优秀开源项目
4. [GVP](https://gitee.com/gvp) 全称是码云最有价值开源项目,是码云综合评定出的优秀开源项目
5. 码云官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help)
6. 码云封面人物是一档用来展示码云会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)
## Supported Linux Distributions
At the moment we officially support the following Linux distributions:
* Ubuntu 16.04 (xenial)
* Ubuntu 18.04 (bionic)
However all other distributions supporting snap packages should work as
well as long as they provide the mandatory kernel modules (see kernel/).
## Install and Run Android Applications
TBD
## Build from source
### Requirements
To build the Anbox runtime itself there is nothing special to know. We're using
cmake as build system. A few build dependencies need to be present on your host
system:
* libdbus
* google-mock
* google-test
* libboost
* libboost-filesystem
* libboost-log
* libboost-iostreams
* libboost-program-options
* libboost-system
* libboost-test
* libboost-thread
* libcap
* libsystemd
* mesa (libegl1, libgles2)
* libsdl2
* libprotobuf
* protobuf-compiler
* lxc (>= 3.0)
On an Ubuntu system you can install all build dependencies with the following
command:
```
$ sudo apt install build-essential cmake cmake-data debhelper dbus google-mock \
libboost-dev libboost-filesystem-dev libboost-log-dev libboost-iostreams-dev \
libboost-program-options-dev libboost-system-dev libboost-test-dev \
libboost-thread-dev libcap-dev libsystemd-dev libegl1-mesa-dev \
libgles2-mesa-dev libglm-dev libgtest-dev liblxc1 \
libproperties-cpp-dev libprotobuf-dev libsdl2-dev libsdl2-image-dev lxc-dev \
pkg-config protobuf-compiler
```
We recommend Ubuntu 18.04 (bionic) with **GCC 7.x** as your build environment.
### Build
Afterwards you can build Anbox with
```
$ git clone https://github.com/anbox/anbox.git
$ cd anbox
$ mkdir build
$ cd build
$ cmake ..
$ make
```
A simple
```
$ sudo make install
```
will install the necessary bits into your system.
If you want to build the anbox snap instead you can do this with the following
steps:
```
$ mkdir android-images
$ cp /path/to/android.img android-images/android.img
$ snapcraft
```
The result will be a .snap file you can install on a system supporting snaps
```
$ snap install --dangerous --devmode anbox_1_amd64.snap
```
## Run Anbox
Running Anbox from a local build requires a few more things you need to know
about. Please have a look at the ["Runtime Setup"](docs/runtime-setup.md)
documentation.
## Documentation
You will find additional documentation for Anbox in the *docs* subdirectory
of the project source.
Interesting things to have a look at
* [Runtime Setup](docs/runtime-setup.md)
* [Build Android image](docs/build-android.md)
* [Generate Android emugl source](docs/generate-emugl-source.md)
## Reporting bugs
If you have found an issue with Anbox, please [file a bug](https://github.com/anbox/anbox/issues/new).
## Get in Touch
If you want to get in contact with the developers please feel free to join the
*#anbox* IRC channel on [Freenode](https://freenode.net/).
## Copyright and Licensing
Anbox reuses code from other projects like the Android QEMU emulator. These
projects are available in the external/ subdirectory with the licensing terms
included.
The Anbox source itself, if not stated differently in the relevant source files,
is licensed under the terms of the GPLv3 license.
include_directories(
${CMAKE_SOURCE_DIR}
${CMAKE_SOURCE_DIR}/src
${CMAKE_BINARY_DIR}/src)
set(ANBOXD_SOURCES
${CMAKE_SOURCE_DIR}/src/anbox/rpc/message_processor.cpp
${CMAKE_SOURCE_DIR}/src/anbox/rpc/pending_call_cache.cpp
${CMAKE_SOURCE_DIR}/src/anbox/common/fd.cpp
service/activity_manager_interface.cpp
service/platform_service.cpp
service/platform_service_interface.cpp
service/platform_api_stub.cpp
service/android_api_skeleton.cpp
service/message_processor.cpp
service/local_socket_connection.cpp
service/host_connector.cpp
service/daemon.cpp
service/main.cpp)
add_executable(anboxd ${ANBOXD_SOURCES})
target_link_libraries(anboxd
pthread
process-cpp
anbox-protobuf)
set(HWCOMPOSER_SOURCES
hwcomposer/hwcomposer.cpp)
add_library(hwcomposer.anbox SHARED ${HWCOMPOSER_SOURCES})
set(AUDIO_SOURCES
audio/audio_hw.cpp)
add_library(audio.goldfish SHARED ${AUDIO_SOURCES})
# As we're adding Android specific bits in this project we can't
# build this safely within default build anymore. We keep this
# for easy integration into used IDEs.
set_target_properties(anboxd
PROPERTIES EXCLUDE_FROM_ALL 1 EXCLUDE_FROM_DEFAULT_BUILD 1)
set_target_properties(hwcomposer.anbox
PROPERTIES EXCLUDE_FROM_ALL 1 EXCLUDE_FROM_DEFAULT_BUILD 1)
set_target_properties(audio.goldfish
PROPERTIES EXCLUDE_FROM_ALL 1 EXCLUDE_FROM_DEFAULT_BUILD 1)
service anboxd /system/bin/anboxd
class core
service anbox-log-dumper /system/bin/logcat -f /data/system.log -r 2048 -n 4
class core
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_STATIC_JAVA_LIBRARIES := \
android-common \
android-support-v13
LOCAL_SRC_FILES := $(call all-java-files-under, src)
# LOCAL_SDK_VERSION := current
LOCAL_PACKAGE_NAME := AnboxAppMgr
LOCAL_CERTIFICATE := shared
LOCAL_PRIVILEGED_MODULE := true
LOCAL_OVERRIDES_PACKAGES := \
Home \
Launcher2 \
Launcher3 \
LatinIME \
QuickSearchBox
include $(BUILD_PACKAGE)
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="org.anbox.appmgr">
<application
android:name="org.anbox.appmgr.MainApplication">
<activity
android:name=".LauncherActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.HOME"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
<activity
android:name=".AppViewActivity"
android:label="@string/app_name"
android:excludeFromRecents="true">
</activity>
<service
android:name=".LauncherService"
android:exported="false">
</service>
<receiver android:name=".PackageEventReceiver">
<intent-filter>
<action android:name="android.intent.action.PACKAGE_ADDED"/>
<action android:name="android.intent.action.PACAKGE_REMOVED"/>
<action android:name="android.intent.action.PACKAGE_CHANGED"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:scheme="package"/>
</intent-filter>
</receiver>
</application>
</manifest>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
tools:context=".AppViewActivity">
<fragment
android:layout_width="match_parent"
android:layout_height="match_parent"
android:name="org.anbox.appmgr.AppsGridFragment"
android:id="@+id/apps_grid" />
</RelativeLayout>
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2007 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.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView android:id="@+id/icon"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_gravity="center_horizontal"/>
<TextView android:id="@+id/text"
android:layout_gravity="center_horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:singleLine="true"
android:gravity="center"
android:textColor="@android:color/black"
android:textSize="14sp"
/>
</LinearLayout>
<resources>
<!-- Default screen margins, per the Android Design guidelines. -->
<dimen name="activity_horizontal_margin">16dp</dimen>
<dimen name="activity_vertical_margin">16dp</dimen>
</resources>
<resources>
<string name="app_name">Anbox Application Manager</string>
</resources>
/*
* The MIT License (MIT)
*
* Copyright 2016 Arnab Chakraborty. http://arnab.ch
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the Software
* without restriction, including without limitation the rights to use, copy, modify,
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be included in all copies
* or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package org.anbox.appmgr;
import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.Collection;
/**
* Created by Arnab Chakraborty
*/
public class AppListAdapter extends ArrayAdapter<AppModel> {
private final LayoutInflater mInflater;
public AppListAdapter (Context context) {
super(context, android.R.layout.simple_list_item_2);
mInflater = LayoutInflater.from(context);
}
public void setData(ArrayList<AppModel> data) {
clear();
if (data != null) {
addAll(data);
}
}
@Override
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public void addAll(Collection<? extends AppModel> items) {
//If the platform supports it, use addAll, otherwise add in loop
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
super.addAll(items);
}else{
for(AppModel item: items){
super.add(item);
}
}
}
/**
* Populate new items in the list.
*/
@Override public View getView(int position, View convertView, ViewGroup parent) {
View view;
if (convertView == null) {
view = mInflater.inflate(R.layout.list_item_icon_text, parent, false);
} else {
view = convertView;
}
AppModel item = getItem(position);
((ImageView)view.findViewById(R.id.icon)).setImageDrawable(item.getIcon());
((TextView)view.findViewById(R.id.text)).setText(item.getLabel());
return view;
}
}
/*
* The MIT License (MIT)
*
* Copyright 2016 Arnab Chakraborty. http://arnab.ch
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the Software
* without restriction, including without limitation the rights to use, copy, modify,
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be included in all copies
* or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package org.anbox.appmgr;
import android.os.Bundle;
import android.support.v4.app.ListFragment;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.Loader;
import java.util.ArrayList;
/**
* Created by Arnab Chakraborty
*/
public class AppListFragment extends ListFragment implements LoaderManager.LoaderCallbacks<ArrayList<AppModel>> {
AppListAdapter mAdapter;
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setEmptyText("No Applications");
mAdapter = new AppListAdapter(getActivity());
setListAdapter(mAdapter);
// till the data is loaded display a spinner
setListShown(false);
// create the loader to load the apps list in background
getLoaderManager().initLoader(0, null, this);
}
@Override
public Loader<ArrayList<AppModel>> onCreateLoader(int id, Bundle bundle) {
return new AppsLoader(getActivity());
}
@Override
public void onLoadFinished(Loader<ArrayList<AppModel>> loader, ArrayList<AppModel> apps) {
mAdapter.setData(apps);
if (isResumed()) {
setListShown(true);
} else {
setListShownNoAnimation(true);
}
}
@Override
public void onLoaderReset(Loader<ArrayList<AppModel>> loader) {
mAdapter.setData(null);
}
}
/*
* The MIT License (MIT)
*
* Copyright 2016 Arnab Chakraborty. http://arnab.ch
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the Software
* without restriction, including without limitation the rights to use, copy, modify,
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be included in all copies
* or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package org.anbox.appmgr;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.graphics.drawable.Drawable;
import java.io.File;
/**
* @credit http://developer.android.com/reference/android/content/AsyncTaskLoader.html
*/
public class AppModel {
private final Context mContext;
private final ApplicationInfo mInfo;
private String mAppLabel;
private Drawable mIcon;
private boolean mMounted;
private final File mApkFile;
public AppModel(Context context, ApplicationInfo info) {
mContext = context;
mInfo = info;
mApkFile = new File(info.sourceDir);
}
public ApplicationInfo getAppInfo() {
return mInfo;
}
public String getApplicationPackageName() {
return getAppInfo().packageName;
}
public String getLabel() {
return mAppLabel;
}
public Drawable getIcon() {
if (mIcon == null) {
if (mApkFile.exists()) {
mIcon = mInfo.loadIcon(mContext.getPackageManager());
return mIcon;
} else {
mMounted = false;
}
} else if (!mMounted) {
// If the app wasn't mounted but is now mounted, reload
// its icon.
if (mApkFile.exists()) {
mMounted = true;
mIcon = mInfo.loadIcon(mContext.getPackageManager());
return mIcon;
}
} else {
return mIcon;
}
return mContext.getResources().getDrawable(android.R.drawable.sym_def_app_icon);
}
void loadLabel(Context context) {
if (mAppLabel == null || !mMounted) {
if (!mApkFile.exists()) {
mMounted = false;
mAppLabel = mInfo.packageName;
} else {
mMounted = true;
CharSequence label = mInfo.loadLabel(context.getPackageManager());
mAppLabel = label != null ? label.toString() : mInfo.packageName;
}
}
}
}
/*
* Copyright (C) 2016 Simon Fels <morphis@gravedo.de>
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3, as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranties of
* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package org.anbox.appmgr;
import android.os.Bundle;
import android.util.Log;
import android.support.v4.app.FragmentActivity;
public final class AppViewActivity extends FragmentActivity {
private static final String TAG = "AnboxAppView";
@Override
public void onCreate(Bundle info) {
super.onCreate(info);
setContentView(R.layout.app_view);
Log.i(TAG, "Created application view activity");
}
@Override
public void onDestroy() {
Log.i(TAG, "Destroying application view activity");
super.onDestroy();
}
}
/*
* The MIT License (MIT)
*
* Copyright 2016 Arnab Chakraborty. http://arnab.ch
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the Software
* without restriction, including without limitation the rights to use, copy, modify,
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be included in all copies
* or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package org.anbox.appmgr;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.Loader;
import android.view.View;
import android.widget.GridView;
import java.util.ArrayList;
/**
* Created by Arnab Chakraborty
*/
public class AppsGridFragment extends GridFragment implements LoaderManager.LoaderCallbacks<ArrayList<AppModel>> {
AppListAdapter mAdapter;
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setEmptyText("No Applications");
mAdapter = new AppListAdapter(getActivity());
setGridAdapter(mAdapter);
// till the data is loaded display a spinner
setGridShown(false);
// create the loader to load the apps list in background
getLoaderManager().initLoader(0, null, this);
}
@Override
public Loader<ArrayList<AppModel>> onCreateLoader(int id, Bundle bundle) {
return new AppsLoader(getActivity());
}
@Override
public void onLoadFinished(Loader<ArrayList<AppModel>> loader, ArrayList<AppModel> apps) {
mAdapter.setData(apps);
if (isResumed()) {
setGridShown(true);
} else {
setGridShownNoAnimation(true);
}
}
@Override
public void onLoaderReset(Loader<ArrayList<AppModel>> loader) {
mAdapter.setData(null);
}
@Override
public void onGridItemClick(GridView g, View v, int position, long id) {
AppModel app = (AppModel) getGridAdapter().getItem(position);
if (app != null) {
Intent intent = getActivity().getPackageManager().getLaunchIntentForPackage(app.getApplicationPackageName());
if (intent != null) {
startActivity(intent);
}
}
}
}
/*
* The MIT License (MIT)
*
* Copyright 2016 Arnab Chakraborty. http://arnab.ch
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the Software
* without restriction, including without limitation the rights to use, copy, modify,
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be included in all copies
* or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package org.anbox.appmgr;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.support.v4.content.AsyncTaskLoader;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Comparator;
/**
* @credit http://developer.android.com/reference/android/content/AsyncTaskLoader.html
*/
public class AppsLoader extends AsyncTaskLoader<ArrayList<AppModel>> {
ArrayList<AppModel> mInstalledApps;
final PackageManager mPm;
PackageIntentReceiver mPackageObserver;
public AppsLoader(Context context) {
super(context);
mPm = context.getPackageManager();
}
@Override
public ArrayList<AppModel> loadInBackground() {
// retrieve the list of installed applications
List<ApplicationInfo> apps = mPm.getInstalledApplications(0);
if (apps == null) {
apps = new ArrayList<ApplicationInfo>();
}
final Context context = getContext();
// create corresponding apps and load their labels
ArrayList<AppModel> items = new ArrayList<AppModel>(apps.size());
for (int i = 0; i < apps.size(); i++) {
String pkg = apps.get(i).packageName;
// only apps which are launchable
if (context.getPackageManager().getLaunchIntentForPackage(pkg) != null) {
AppModel app = new AppModel(context, apps.get(i));
app.loadLabel(context);
items.add(app);
}
}
// sort the list
Collections.sort(items, ALPHA_COMPARATOR);
return items;
}
@Override
public void deliverResult(ArrayList<AppModel> apps) {
if (isReset()) {
// An async query came in while the loader is stopped. We
// don't need the result.
if (apps != null) {
onReleaseResources(apps);
}
}
ArrayList<AppModel> oldApps = apps;
mInstalledApps = apps;
if (isStarted()) {
// If the Loader is currently started, we can immediately
// deliver its results.
super.deliverResult(apps);
}
// At this point we can release the resources associated with
// 'oldApps' if needed; now that the new result is delivered we
// know that it is no longer in use.
if (oldApps != null) {
onReleaseResources(oldApps);
}
}
@Override
protected void onStartLoading() {
if (mInstalledApps != null) {
// If we currently have a result available, deliver it
// immediately.
deliverResult(mInstalledApps);
}
// watch for changes in app install and uninstall operation
if (mPackageObserver == null) {
mPackageObserver = new PackageIntentReceiver(this);
}
if (takeContentChanged() || mInstalledApps == null ) {
// If the data has changed since the last time it was loaded
// or is not currently available, start a load.
forceLoad();
}
}
@Override
protected void onStopLoading() {
// Attempt to cancel the current load task if possible.
cancelLoad();
}
@Override
public void onCanceled(ArrayList<AppModel> apps) {
super.onCanceled(apps);
// At this point we can release the resources associated with 'apps'
// if needed.
onReleaseResources(apps);
}
@Override
protected void onReset() {
// Ensure the loader is stopped
onStopLoading();
// At this point we can release the resources associated with 'apps'
// if needed.
if (mInstalledApps != null) {
onReleaseResources(mInstalledApps);
mInstalledApps = null;
}
// Stop monitoring for changes.
if (mPackageObserver != null) {
getContext().unregisterReceiver(mPackageObserver);
mPackageObserver = null;
}
}
/**
* Helper method to do the cleanup work if needed, for example if we're
* using Cursor, then we should be closing it here
*
* @param apps
*/
protected void onReleaseResources(ArrayList<AppModel> apps) {
// do nothing
}
/**
* Perform alphabetical comparison of application entry objects.
*/
public static final Comparator<AppModel> ALPHA_COMPARATOR = new Comparator<AppModel>() {
private final Collator sCollator = Collator.getInstance();
@Override
public int compare(AppModel object1, AppModel object2) {
return sCollator.compare(object1.getLabel(), object2.getLabel());
}
};
}
package org.anbox.appmgr;
/*
* Created by Thomas Barrasso on 9/11/12.
* Copyright (c) 2012 Loupe Inc.
*
* 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.
*/
import android.content.Context;
import android.content.res.Resources;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.app.Fragment;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AnimationUtils;
import android.widget.AdapterView;
import android.widget.FrameLayout;
import android.widget.GridView;
import android.widget.LinearLayout;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;
/**
* Based on {@link android.app.ListFragment} but adapted for {@link GridView}.
*/
public class GridFragment extends Fragment {
static final int INTERNAL_EMPTY_ID = 0x00ff0001;
static final int INTERNAL_PROGRESS_CONTAINER_ID = 0x00ff0002;
static final int INTERNAL_LIST_CONTAINER_ID = 0x00ff0003;
final private Handler mHandler = new Handler();
final private Runnable mRequestFocus = new Runnable() {
public void run() {
mGrid.focusableViewAvailable(mGrid);
}
};
final private AdapterView.OnItemClickListener mOnClickListener
= new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
onGridItemClick((GridView) parent, v, position, id);
}
};
ListAdapter mAdapter;
GridView mGrid;
View mEmptyView;
TextView mStandardEmptyView;
View mProgressContainer;
View mGridContainer;
CharSequence mEmptyText;
boolean mGridShown;
public GridFragment() { }
/**
* Provide default implementation to return a simple grid view. Subclasses
* can override to replace with their own layout. If doing so, the
* returned view hierarchy <em>must</em> have a GridView whose id
* is {@link android.R.id#list android.R.id.list} and can optionally
* have a sibling view id {@link android.R.id#empty android.R.id.empty}
* that is to be shown when the grid is empty.
*
* <p>If you are overriding this method with your own custom content,
* consider including the standard layout {@link android.R.layout#list_content}
* in your layout file, so that you continue to retain all of the standard
* behavior of ListFragment. In particular, this is currently the only
* way to have the built-in indeterminant progress state be shown.
*/
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final Context context = getActivity();
FrameLayout root = new FrameLayout(context);
// ------------------------------------------------------------------
LinearLayout pframe = new LinearLayout(context);
pframe.setId(INTERNAL_PROGRESS_CONTAINER_ID);
pframe.setOrientation(LinearLayout.VERTICAL);
pframe.setVisibility(View.GONE);
pframe.setGravity(Gravity.CENTER);
ProgressBar progress = new ProgressBar(context, null,
android.R.attr.progressBarStyleLarge);
pframe.addView(progress, new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
root.addView(pframe, new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
// ------------------------------------------------------------------
FrameLayout lframe = new FrameLayout(context);
lframe.setId(INTERNAL_LIST_CONTAINER_ID);
TextView tv = new TextView(getActivity());
tv.setId(INTERNAL_EMPTY_ID);
tv.setGravity(Gravity.CENTER);
lframe.addView(tv, new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
GridView lv = new GridView(getActivity());
lv.setId(android.R.id.list);
lv.setDrawSelectorOnTop(false);
lv.setColumnWidth(convertDpToPixels(60, getActivity()));
lv.setStretchMode(GridView.STRETCH_COLUMN_WIDTH);
lv.setNumColumns(GridView.AUTO_FIT);
lv.setHorizontalSpacing(convertDpToPixels(20, getActivity()));
lv.setVerticalSpacing(convertDpToPixels(20, getActivity()));
lv.setSmoothScrollbarEnabled(true);
// disable overscroll
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
lv.setOverScrollMode(ListView.OVER_SCROLL_NEVER);
}
lframe.addView(lv, new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
root.addView(lframe, new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
// ------------------------------------------------------------------
root.setLayoutParams(new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
return root;
}
/**
* Attach to grid view once the view hierarchy has been created.
*/
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
ensureGrid();
}
/**
* Detach from {@link GridView}
*/
@Override
public void onDestroyView() {
mHandler.removeCallbacks(mRequestFocus);
mGrid = null;
mGridShown = false;
mEmptyView = mProgressContainer = mGridContainer = null;
mStandardEmptyView = null;
super.onDestroyView();
}
public static int convertDpToPixels(float dp, Context context){
Resources resources = context.getResources();
return (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
dp,
resources.getDisplayMetrics()
);
}
/**
* This method will be called when an item in the grid is selected.
* Subclasses should override. Subclasses can call
* getGridView().getItemAtPosition(position) if they need to access the
* data associated with the selected item.
*
* @param g The {@link GridView} where the click happened
* @param v The view that was clicked within the {@link GridView}
* @param position The position of the view in the grid
* @param id The row id of the item that was clicked
*/
public void onGridItemClick(GridView g, View v, int position, long id) {
}
/**
* Provide the cursor for the {@link GridView}.
*/
public void setGridAdapter(ListAdapter adapter) {
final boolean hadAdapter = (mAdapter != null);
mAdapter = adapter;
if (mGrid != null) {
mGrid.setAdapter(adapter);
if (!mGridShown && !hadAdapter) {
// The grid was hidden, and previously didn't have an
// adapter. It is now time to show it.
setGridShown(true, (getView().getWindowToken() != null));
}
}
}
/**
* Set the currently selected grid item to the specified
* position with the adapter's data
*
* @param position
*/
public void setSelection(int position) {
ensureGrid();
mGrid.setSelection(position);
}
/**
* Get the position of the currently selected grid item.
*/
public int getSelectedItemPosition() {
ensureGrid();
return mGrid.getSelectedItemPosition();
}
/**
* Get the cursor row ID of the currently selected grid item.
*/
public long getSelectedItemId() {
ensureGrid();
return mGrid.getSelectedItemId();
}
/**
* Get the activity's {@link GridView} widget.
*/
public GridView getGridView() {
ensureGrid();
return mGrid;
}
/**
* The default content for a ListFragment has a TextView that can
* be shown when the grid is empty. If you would like to have it
* shown, call this method to supply the text it should use.
*/
public void setEmptyText(CharSequence text) {
ensureGrid();
if (mStandardEmptyView == null) {
throw new IllegalStateException("Can't be used with a custom content view");
}
mStandardEmptyView.setText(text);
if (mEmptyText == null) {
mGrid.setEmptyView(mStandardEmptyView);
}
mEmptyText = text;
}
/**
* Control whether the grid is being displayed. You can make it not
* displayed if you are waiting for the initial data to show in it. During
* this time an indeterminant progress indicator will be shown instead.
*
* <p>Applications do not normally need to use this themselves. The default
* behavior of ListFragment is to start with the grid not being shown, only
* showing it once an adapter is given with {@link #setGridAdapter(ListAdapter)}.
* If the grid at that point had not been shown, when it does get shown
* it will be do without the user ever seeing the hidden state.
*
* @param shown If true, the grid view is shown; if false, the progress
* indicator. The initial value is true.
*/
public void setGridShown(boolean shown) {
setGridShown(shown, true);
}
/**
* Like {@link #setGridShown(boolean)}, but no animation is used when
* transitioning from the previous state.
*/
public void setGridShownNoAnimation(boolean shown) {
setGridShown(shown, false);
}
/**
* Control whether the grid is being displayed. You can make it not
* displayed if you are waiting for the initial data to show in it. During
* this time an indeterminant progress indicator will be shown instead.
*
* @param shown If true, the grid view is shown; if false, the progress
* indicator. The initial value is true.
* @param animate If true, an animation will be used to transition to the
* new state.
*/
private void setGridShown(boolean shown, boolean animate) {
ensureGrid();
if (mProgressContainer == null) {
throw new IllegalStateException("Can't be used with a custom content view");
}
if (mGridShown == shown) {
return;
}
mGridShown = shown;
if (shown) {
if (animate) {
mProgressContainer.startAnimation(AnimationUtils.loadAnimation(
getActivity(), android.R.anim.fade_out));
mGridContainer.startAnimation(AnimationUtils.loadAnimation(
getActivity(), android.R.anim.fade_in));
} else {
mProgressContainer.clearAnimation();
mGridContainer.clearAnimation();
}
mProgressContainer.setVisibility(View.GONE);
mGridContainer.setVisibility(View.VISIBLE);
} else {
if (animate) {
mProgressContainer.startAnimation(AnimationUtils.loadAnimation(
getActivity(), android.R.anim.fade_in));
mGridContainer.startAnimation(AnimationUtils.loadAnimation(
getActivity(), android.R.anim.fade_out));
} else {
mProgressContainer.clearAnimation();
mGridContainer.clearAnimation();
}
mProgressContainer.setVisibility(View.VISIBLE);
mGridContainer.setVisibility(View.GONE);
}
}
/**
* Get the ListAdapter associated with this activity's {@link GridView}.
*/
public ListAdapter getGridAdapter() {
return mAdapter;
}
private void ensureGrid() {
if (mGrid != null) {
return;
}
View root = getView();
if (root == null) {
throw new IllegalStateException("Content view not yet created");
}
if (root instanceof GridView) {
mGrid = (GridView) root;
} else {
mStandardEmptyView = (TextView)root.findViewById(INTERNAL_EMPTY_ID);
if (mStandardEmptyView == null) {
mEmptyView = root.findViewById(android.R.id.empty);
} else {
mStandardEmptyView.setVisibility(View.GONE);
}
mProgressContainer = root.findViewById(INTERNAL_PROGRESS_CONTAINER_ID);
mGridContainer = root.findViewById(INTERNAL_LIST_CONTAINER_ID);
View rawGridView = root.findViewById(android.R.id.list);
if (!(rawGridView instanceof GridView)) {
if (rawGridView == null) {
throw new RuntimeException(
"Your content must have a GridView whose id attribute is " +
"'android.R.id.list'");
}
throw new RuntimeException(
"Content has view with id attribute 'android.R.id.list' "
+ "that is not a GridView class");
}
mGrid = (GridView) rawGridView;
if (mEmptyView != null) {
mGrid.setEmptyView(mEmptyView);
} else if (mEmptyText != null) {
mStandardEmptyView.setText(mEmptyText);
mGrid.setEmptyView(mStandardEmptyView);
}
}
mGridShown = true;
mGrid.setOnItemClickListener(mOnClickListener);
if (mAdapter != null) {
ListAdapter adapter = mAdapter;
mAdapter = null;
setGridAdapter(adapter);
} else {
// We are starting without an adapter, so assume we won't
// have our data right away and start with the progress indicator.
if (mProgressContainer != null) {
setGridShown(false, false);
}
}
mHandler.post(mRequestFocus);
}
}
/*
* Copyright (C) 2016 Simon Fels <morphis@gravedo.de>
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3, as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranties of
* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package org.anbox.appmgr;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.content.Intent;
public final class LauncherActivity extends Activity {
private static final String TAG = "AnboxAppMgr";
@Override
public void onCreate(Bundle info) {
super.onCreate(info);
Intent intent = new Intent(this, LauncherService.class);
startService(intent);
Log.i(TAG, "Created launcher activity");
}
@Override
public void onDestroy() {
Log.i(TAG, "Destroyed launcher activity");
Intent intent = new Intent(this, LauncherService.class);
stopService(intent);
super.onDestroy();
}
}
/*
* Copyright (C) 2016 Simon Fels <morphis@gravedo.de>
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3, as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranties of
* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package org.anbox.appmgr;
import android.app.Service;
import android.util.Log;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.IBinder;
public final class LauncherService extends Service {
public static final String TAG = "AnboxAppMgr";
private PlatformService mPlatformService;
private PackageEventReceiver mPkgEventReceiver;
public LauncherService() {
super();
Log.i(TAG, "Service created");
}
@Override
public void onCreate() {
mPlatformService = new PlatformService(getBaseContext());
// Send the current list of applications over to the host so
// it can rebuild its list of available applications.
mPlatformService.sendApplicationListUpdate();
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_PACKAGE_ADDED);
filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
filter.addDataScheme("package");
mPkgEventReceiver = new PackageEventReceiver();
registerReceiver(mPkgEventReceiver, filter);
Log.i(TAG, "Service started");
}
@Override
public void onDestroy() {
Log.i(TAG, "Service stopped");
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
/*
* Copyright (C) 2016 Simon Fels <morphis@gravedo.de>
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3, as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranties of
* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package org.anbox.appmgr;
import android.app.Application;
public final class MainApplication extends Application {
}
/*
* Copyright (C) 2016 Simon Fels <morphis@gravedo.de>
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3, as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranties of
* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package org.anbox.appmgr;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.util.Log;
public class PackageEventReceiver extends BroadcastReceiver {
private static final String TAG = "AnboxAppMgr";
private PlatformService mPlatformService;
private String getPackageName(Intent intent) {
Uri uri = intent.getData();
String package_name = (uri != null ? uri.getSchemeSpecificPart() : null);
return package_name;
}
@Override
public void onReceive(Context context, Intent intent) {
if (mPlatformService == null)
mPlatformService = new PlatformService(context);
if (intent.getAction() == Intent.ACTION_PACKAGE_ADDED ||
intent.getAction() == Intent.ACTION_PACKAGE_CHANGED) {
// Send updated list of applications to the host so that it
// can update the list of applications available for the user.
mPlatformService.sendApplicationListUpdate();
} else if (intent.getAction() == Intent.ACTION_PACKAGE_REMOVED) {
// Only send notification when package got removed and not replaced
if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
mPlatformService.notifyPackageRemoved(getPackageName(intent));
}
}
}
}
/*
* The MIT License (MIT)
*
* Copyright 2016 Arnab Chakraborty. http://arnab.ch
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the Software
* without restriction, including without limitation the rights to use, copy, modify,
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be included in all copies
* or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package org.anbox.appmgr;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
/**
* Helper class to look for interesting changes to the installed apps
* so that the loader can be updated.
*
* @Credit http://developer.android.com/reference/android/content/AsyncTaskLoader.html
*/
public class PackageIntentReceiver extends BroadcastReceiver {
final AppsLoader mLoader;
public PackageIntentReceiver(AppsLoader loader) {
mLoader = loader;
IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
filter.addDataScheme("package");
mLoader.getContext().registerReceiver(this, filter);
// Register for events related to sdcard installation.
IntentFilter sdFilter = new IntentFilter();
sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
mLoader.getContext().registerReceiver(this, sdFilter);
}
@Override public void onReceive(Context context, Intent intent) {
// Tell the loader about the change.
mLoader.onContentChanged();
}
}
/*
* Copyright (C) 2016 Simon Fels <morphis@gravedo.de>
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3, as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranties of
* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package org.anbox.appmgr;
import android.os.ServiceManager;
import android.os.IBinder;
import android.os.Parcel;
import android.os.RemoteException;
import android.util.Log;
import android.content.Intent;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.ApplicationInfo;
import android.net.Uri;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import java.util.List;
import java.io.ByteArrayOutputStream;
public final class PlatformService {
private static final String TAG = "AnboxAppMgr";
private static final String SERVICE_NAME = "org.anbox.PlatformService";
private static final String DESCRIPTOR = "org.anbox.IPlatformService";
private static final int TRANSACTION_updateApplicationList = (IBinder.FIRST_CALL_TRANSACTION + 2);
private IBinder mService = null;
private PackageManager mPm = null;
private void connectService() {
if (mService != null)
return;
mService = ServiceManager.getService(SERVICE_NAME);
}
public PlatformService(Context context) {
if (context != null) {
mPm = context.getPackageManager();
} else {
Log.w(TAG, "No context available");
}
Log.i(TAG, "Connected to platform service");
}
public void notifyPackageRemoved(String packageName) {
connectService();
if (mService == null)
return;
Log.i(TAG, "Sending package removed notification to host service");
Parcel data = Parcel.obtain();
data.writeInterfaceToken(DESCRIPTOR);
// No added or updated applications to report
data.writeInt(0);
// .. but a single removed application
data.writeInt(1);
data.writeString(packageName);
Parcel reply = Parcel.obtain();
try {
mService.transact(TRANSACTION_updateApplicationList, data, reply, 0);
}
catch (RemoteException ex) {
Log.w(TAG, "Failed to send updatePackageList request to remote binder service: " + ex.getMessage());
}
}
public void sendApplicationListUpdate() {
connectService();
if (mPm == null || mService == null)
return;
Parcel data = Parcel.obtain();
data.writeInterfaceToken(DESCRIPTOR);
List<ApplicationInfo> apps = mPm.getInstalledApplications(0);
data.writeInt(apps.size());
for (int n = 0; n < apps.size(); n++) {
ApplicationInfo appInfo = apps.get(n);
Intent launchIntent = mPm.getLaunchIntentForPackage(appInfo.packageName);
if (launchIntent == null)
continue;
Drawable icon = null;
try {
icon = mPm.getApplicationIcon(appInfo.packageName);
}
catch (PackageManager.NameNotFoundException ex) {
continue;
}
if (icon == null)
continue;
String name = appInfo.name;
CharSequence label = appInfo.loadLabel(mPm);
if (label != null)
name = label.toString();
data.writeString(name);
data.writeString(appInfo.packageName);
data.writeString(launchIntent.getAction());
if (launchIntent.getData() != null)
data.writeString(launchIntent.getData().toString());
else
data.writeString("");
data.writeString(launchIntent.getType());
data.writeString(launchIntent.getComponent().getPackageName());
data.writeString(launchIntent.getComponent().getClassName());
data.writeInt(launchIntent.getCategories().size());
for (String category : launchIntent.getCategories())
data.writeString(category);
Bitmap iconBitmap = drawableToBitmap(icon);
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
iconBitmap.compress(Bitmap.CompressFormat.PNG, 90, outStream);
data.writeByteArray(outStream.toByteArray());
}
// We don't have any removed applications to include in the update
data.writeInt(0);
Parcel reply = Parcel.obtain();
try {
mService.transact(TRANSACTION_updateApplicationList, data, reply, 0);
}
catch (RemoteException ex) {
Log.w(TAG, "Failed to send updatePackageList request to remote binder service: " + ex.getMessage());
}
}
private Bitmap drawableToBitmap(Drawable drawable) {
if (drawable instanceof BitmapDrawable)
return ((BitmapDrawable)drawable).getBitmap();
Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
drawable.draw(canvas);
return bitmap;
}
}
Copyright (c) 2008-2009, 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.
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.
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
# hardware-audio #
This module contains the Anbox Android Audio HAL source code.
It is part of the Anbox Android delivery for Android.
## Description ##
This is the first version of the module for android.
It generates the library "audio.primary.goldfish.so" used to implement vendor-specific functionalities for the Android default Audio service.
The configuration file audio_policy.conf should be on the "hardware/libhardware_legacy" folder. It defines the default configuration states (input, output...) of the driver. More details can be found in audio_policy.conf. The output/Input parameter in audio_policy.conf should be set as follow:
outputs {
primary {
sampling_rates 44100
channel_masks AUDIO_CHANNEL_OUT_STEREO
formats AUDIO_FORMAT_PCM_16_BIT
devices AUDIO_DEVICE_OUT_SPEAKER
flags AUDIO_OUTPUT_FLAG_PRIMARY
}
}
inputs {
primary {
sampling_rates 48000
channel_masks AUDIO_CHANNEL_IN_MONO
formats AUDIO_FORMAT_PCM_16_BIT
devices AUDIO_DEVICE_IN_BUILTIN_MIC
}
}
Warning: Our audio chip only support 48kHz or 44.1kHz, in order to get high quality recording,
so we choose 48kHz.If you want to change inputs sampling_rates, you must modify alsa_helper.h,it should be on the "anbox/src/anbox/audio/" folder.
source codes as follow:
/**
* DEFAULT_SAMPLE_RATE is used for recording sample rate.
* Our audio chip only support 48kHz or 44.1kHz, in order to get high quality recording,
* so we choose 48kHz. If you want to modify sample rate, please also modify
* hardware/libhardware_legacy/audio/audio_policy.conf and DEFAULT_PERIOD_FRAMES.
* e.g inputs partion config as follow:
* inputs {
* primary {
* sampling_rates 48000
* channel_masks AUDIO_CHANNEL_IN_MONO
* formats AUDIO_FORMAT_PCM_16_BIT
* devices AUDIO_DEVICE_IN_BUILTIN_MIC
* }
* }
*/
const int DEFAULT_SAMPLE_RATE = 48000; // record sample rate using 48kHz
const int DEFAULT_PERIOD_FRAMES = 480; // sample rate 48kHz and read 10ms pcm data
Please see the release notes for more details.
## Documentation ##
* The [release notes][] provide information on the release.
* The [distribution package][] provides detailed information on how to use this delivery.
## Dependencies ##
This module can not be used alone. It is part of the Anbox android delivery for Android.
It provides the audio library used by the default implementation of android. And it need to connect with
local socket server which is start with anbox session-manager. which has to be added in CMakeLists.txt as follow:
```
include_directories(
...
/usr/include/alsa/
)
add_library(anbox-protobuf
STATIC
...
target_link_libraries(anbox-protobuf
${PROTOBUF_LITE_LIBRARIES}
/usr/lib/aarch64-linux-gnu/libasound.so
)
set(SOURCES
...
anbox/audio/alsa_helper.h
anbox/audio/alsa_helper.cpp
anbox/platform/alsa/audio_source.h
anbox/platform/alsa/audio_source.cpp
)
```
## Contents ##
This directory contains the sources and the associated Android makefile to generate the audio.primary.goldfish.so library.
### Audio Playback details
the graphics that explains the details of audio playback is as follows:
______________
| | pthread_mutex_lock(&out->lock)
| out_write | pthread_mutex_unlock(&out->lock)
|______________|
|
|write to queue head
|
|<---live--------->|head
_______|__________________v________________________
| |111111111111111111| | Circular Queue
|_______|___________________________________________|
|tail
|
| read from queue tail
|
|
__V________________
| | pthread_mutex_lock(&out->lock)
thread| out_write_worker | pthread_mutex_unlock(&out->lock)
|___________________| write
|
|local socket connect
|
|
__V________________
| |
|anbox socket server|
|___________________|
|
|
|
__V________________
| |
|host audio driver |
|___________________|
### Sound recording details
the graphics that explains the details of audio recording is as follows:
______________
| | pthread_mutex_lock(&in->lock)
| in_read | pthread_mutex_unlock(&in->lock)
|_____^________|
|
| read from queue tail
|
tail |<---live--------->|
_______|__________________v_________________________
| |111111111111111111| | Circular Queue
|_______|__________________^_________________________|
|head
|
|write to queue head
|
|
_______________|__
| | pthread_mutex_lock(&in->lock)
thread| in_read_worker | pthread_mutex_unlock(&in->lock)
|____^______________| read
|
|local socket connect
|
|
___________________
| |
|anbox socket server|
|____^______________|
|
|
|
_____|_____________
| |
|host audio driver |
|___________________|
## License ##
This module is distributed under the Apache License, Version 2.0 found in the [LICENSE](./LICENSE)file.
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
/*
* Copyright (C) 2013 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.
*/
#ifndef JPEGSTUB_H_
#define JPEGSTUB_H_
extern "C" {
struct JpegStub {
void* mInternalEncoder;
void* mInternalStream;
};
void JpegStub_init(JpegStub* stub, int* strides);
void JpegStub_cleanup(JpegStub* stub);
int JpegStub_compress(JpegStub* stub, const void* image,
int width, int height, int quality);
void JpegStub_getCompressedImage(JpegStub* stub, void* buff);
size_t JpegStub_getCompressedSize(JpegStub* stub);
};
#endif // JPEGSTUB_H_
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
# Android fstab file.
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册