diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index e5e871072..1fec72de9 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -21,6 +21,7 @@
+
\ No newline at end of file
diff --git a/app/src/main/java/com/topjohnwu/magisk/AboutActivity.java b/app/src/main/java/com/topjohnwu/magisk/AboutActivity.java
new file mode 100644
index 000000000..68f10f609
--- /dev/null
+++ b/app/src/main/java/com/topjohnwu/magisk/AboutActivity.java
@@ -0,0 +1,146 @@
+package com.topjohnwu.magisk;
+
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.support.v7.app.ActionBar;
+import android.support.v7.app.AlertDialog;
+import android.support.v7.app.AppCompatActivity;
+import android.support.v7.widget.Toolbar;
+import android.text.Html;
+import android.text.TextUtils;
+import android.text.method.LinkMovementMethod;
+import android.view.View;
+import android.widget.TextView;
+
+import com.topjohnwu.magisk.utils.RowItem;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import butterknife.BindView;
+import butterknife.ButterKnife;
+
+public class AboutActivity extends AppCompatActivity {
+
+ private static final String SOURCE_CODE_URL = "https://github.com/topjohnwu/MagiskManager";
+ private static final String XDA_THREAD = "http://forum.xda-developers.com/android/software/mod-magisk-v1-universal-systemless-t3432382";
+
+ @BindView(R.id.toolbar) Toolbar toolbar;
+
+ @BindView(R.id.app_version_info) RowItem appVersionInfo;
+ @BindView(R.id.app_changelog) RowItem appChangelog;
+ @BindView(R.id.app_developers) RowItem appDevelopers;
+ @BindView(R.id.app_translators) RowItem appTranslators;
+ @BindView(R.id.app_source_code) RowItem appSourceCode;
+ @BindView(R.id.support_thread) RowItem supportThread;
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_about);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
+ }
+ ButterKnife.bind(this);
+
+ setSupportActionBar(toolbar);
+ toolbar.setNavigationOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ finish();
+ }
+ });
+
+ ActionBar ab = getSupportActionBar();
+ if (ab != null) {
+ ab.setTitle(R.string.about);
+ ab.setDisplayHomeAsUpEnabled(true);
+ }
+
+ appVersionInfo.setSummary(BuildConfig.VERSION_NAME);
+
+ String changes = null;
+ try {
+ InputStream is = getAssets().open("changelog.html");
+ int size = is.available();
+
+ byte[] buffer = new byte[size];
+ is.read(buffer);
+ is.close();
+
+ changes = new String(buffer);
+ } catch (IOException ignored) {
+ }
+
+ appChangelog.removeSummary();
+ if (changes == null) {
+ appChangelog.setVisibility(View.GONE);
+ } else {
+ final String finalChanges = changes;
+ appChangelog.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ AlertDialog d = new AlertDialog.Builder(AboutActivity.this)
+ .setTitle(R.string.app_changelog)
+ .setMessage(Html.fromHtml(finalChanges))
+ .setPositiveButton(android.R.string.ok, null)
+ .create();
+
+ d.show();
+
+ //noinspection ConstantConditions
+ ((TextView) d.findViewById(android.R.id.message)).setMovementMethod(LinkMovementMethod.getInstance());
+ }
+ });
+ }
+
+ appDevelopers.removeSummary();
+ appDevelopers.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ AlertDialog d = new AlertDialog.Builder(AboutActivity.this)
+ .setTitle(R.string.app_developers)
+ .setMessage(Html.fromHtml(getString(R.string.app_developers_)))
+ .setPositiveButton(android.R.string.ok, null)
+ .create();
+
+ d.show();
+ //noinspection ConstantConditions
+ ((TextView) d.findViewById(android.R.id.message)).setMovementMethod(LinkMovementMethod.getInstance());
+ }
+ });
+
+ String translators = getString(R.string.translators);
+ if (TextUtils.isEmpty(translators)) {
+ appTranslators.setVisibility(View.GONE);
+ } else {
+ appTranslators.setSummary(translators);
+ }
+
+ appSourceCode.removeSummary();
+ appSourceCode.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(SOURCE_CODE_URL)));
+ }
+ });
+
+ supportThread.removeSummary();
+ supportThread.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(XDA_THREAD)));
+ }
+ });
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+
+ getWindow().setStatusBarColor(getResources().getColor(R.color.primary_dark));
+ }
+}
diff --git a/app/src/main/java/com/topjohnwu/magisk/WelcomeActivity.java b/app/src/main/java/com/topjohnwu/magisk/WelcomeActivity.java
index 964f6f71e..72b9dbaa6 100644
--- a/app/src/main/java/com/topjohnwu/magisk/WelcomeActivity.java
+++ b/app/src/main/java/com/topjohnwu/magisk/WelcomeActivity.java
@@ -1,5 +1,6 @@
package com.topjohnwu.magisk;
+import android.content.Intent;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
@@ -130,6 +131,9 @@ public class WelcomeActivity extends AppCompatActivity implements NavigationView
setTitle(R.string.log);
navFragment = new LogFragment();
break;
+ case R.id.app_about:
+ startActivity(new Intent(this, AboutActivity.class));
+ return;
}
if (navFragment != null) {
diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/RowItem.java b/app/src/main/java/com/topjohnwu/magisk/utils/RowItem.java
new file mode 100644
index 000000000..96c7d2f4e
--- /dev/null
+++ b/app/src/main/java/com/topjohnwu/magisk/utils/RowItem.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2016 dvdandroid
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.topjohnwu.magisk.utils;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.topjohnwu.magisk.R;
+
+/**
+ * @author dvdandroid
+ */
+public class RowItem extends LinearLayout {
+
+ private final String title;
+ private final Drawable icon;
+
+ private final TextView mTitle;
+ private final TextView mSummary;
+ private final ImageView mIcon;
+
+ private final View mView;
+
+ public RowItem(Context context) {
+ this(context, null);
+ }
+
+ public RowItem(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public RowItem(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ LayoutInflater.from(context).inflate(R.layout.info_item_row, this);
+ TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.RowItem, 0, 0);
+
+ try {
+ title = a.getString(R.styleable.RowItem_text);
+ icon = a.getDrawable(R.styleable.RowItem_icon);
+ } finally {
+ a.recycle();
+ }
+
+ mView = findViewById(R.id.container);
+
+ mTitle = (TextView) findViewById(android.R.id.title);
+ mSummary = (TextView) findViewById(android.R.id.summary);
+ mIcon = (ImageView) findViewById(android.R.id.icon);
+
+ mTitle.setText(title);
+ mIcon.setImageDrawable(icon);
+ }
+
+ @Override
+ public void setOnClickListener(OnClickListener l) {
+ super.setOnClickListener(l);
+
+ mView.setOnClickListener(l);
+ }
+
+ public void setSummary(String s) {
+ mSummary.setText(s);
+ }
+
+ public void removeSummary() {
+ mSummary.setVisibility(GONE);
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_github.xml b/app/src/main/res/drawable/ic_github.xml
new file mode 100644
index 000000000..83be6c04e
--- /dev/null
+++ b/app/src/main/res/drawable/ic_github.xml
@@ -0,0 +1,10 @@
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_history.xml b/app/src/main/res/drawable/ic_history.xml
new file mode 100644
index 000000000..6b9f91a37
--- /dev/null
+++ b/app/src/main/res/drawable/ic_history.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_info_outline.xml b/app/src/main/res/drawable/ic_info_outline.xml
new file mode 100644
index 000000000..2d66b0bf6
--- /dev/null
+++ b/app/src/main/res/drawable/ic_info_outline.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_language.xml b/app/src/main/res/drawable/ic_language.xml
new file mode 100644
index 000000000..85b37743a
--- /dev/null
+++ b/app/src/main/res/drawable/ic_language.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_person.xml b/app/src/main/res/drawable/ic_person.xml
new file mode 100644
index 000000000..234d73d8d
--- /dev/null
+++ b/app/src/main/res/drawable/ic_person.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_xda.xml b/app/src/main/res/drawable/ic_xda.xml
new file mode 100644
index 000000000..918a5497b
--- /dev/null
+++ b/app/src/main/res/drawable/ic_xda.xml
@@ -0,0 +1,9 @@
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_about.xml b/app/src/main/res/layout/activity_about.xml
new file mode 100644
index 000000000..b0249a45c
--- /dev/null
+++ b/app/src/main/res/layout/activity_about.xml
@@ -0,0 +1,118 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_welcome.xml b/app/src/main/res/layout/activity_welcome.xml
index b4f712cbc..00adc40b5 100644
--- a/app/src/main/res/layout/activity_welcome.xml
+++ b/app/src/main/res/layout/activity_welcome.xml
@@ -20,13 +20,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"/>
-
+
diff --git a/app/src/main/res/layout/info_item_row.xml b/app/src/main/res/layout/info_item_row.xml
new file mode 100644
index 000000000..ea51a6de1
--- /dev/null
+++ b/app/src/main/res/layout/info_item_row.xml
@@ -0,0 +1,58 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/toolbar.xml b/app/src/main/res/layout/toolbar.xml
new file mode 100644
index 000000000..4f71581de
--- /dev/null
+++ b/app/src/main/res/layout/toolbar.xml
@@ -0,0 +1,9 @@
+
+
\ No newline at end of file
diff --git a/app/src/main/res/menu/drawer.xml b/app/src/main/res/menu/drawer.xml
index 5bba3eec5..5391193d2 100644
--- a/app/src/main/res/menu/drawer.xml
+++ b/app/src/main/res/menu/drawer.xml
@@ -1,7 +1,9 @@
\ No newline at end of file
diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml
new file mode 100644
index 000000000..d64f2a7d9
--- /dev/null
+++ b/app/src/main/res/values/attrs.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 4b29046c0..b9608f78d 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -37,5 +37,14 @@
Magisk
Module will not be removed at next reboot
Cache modules
+ About
+ Main developers
+ topjohnwu in collaboration with dvdandroid]]>
+ App\'s changelog
+
+ App\'s version
+ Source code
+ App\'s translators
+ Support thread