1
0
mirror of https://github.com/moparisthebest/k-9 synced 2024-11-27 11:42:16 -05:00

Add ckChangeLog to display a change log after an app upgrade

This commit is contained in:
cketti 2013-01-08 09:17:35 +01:00
parent 5ac3d1d5c2
commit f548e822d6
15 changed files with 884 additions and 0 deletions

202
plugins/ckChangeLog/LICENSE Normal file
View File

@ -0,0 +1,202 @@
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
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.

View File

@ -0,0 +1,74 @@
# ckChangeLog - An Android Library to display a Change Log
![Screenshot](https://github.com/cketti/ckChangeLog/raw/master/screenshot_1.png)
![Screenshot](https://github.com/cketti/ckChangeLog/raw/master/screenshot_2.png)
This library provides an easy way to display a change log in your app.
## Features
* Uses a simple XML file as source
* Supports partial translations
Repository at <https://github.com/cketti/ckChangeLog>.
## Usage
1. Create the master change log in `res/raw/changelog.xml`. Formatted like this:
<?xml version="1.0" encoding="utf-8"?>
<changelog>
<release version="1.1" versioncode="11" >
<change>Totally new and shiny version</change>
</release>
<release version="1.0" versioncode="10" >
<change>Fixed: A bug fix</change>
<change>Some other changes I can't quite remember</change>
</release>
<release version="0.1" versioncode="1">
<change>First release</change>
</release>
</changelog>
2. Create translations of this file under language-specific versions of `res/xml`, e.g. `res/xml-de`.
3. Display the change log dialog by putting the following code in your activity's `onCreate()` method:
ChangeLog cl = new ChangeLog(this);
if (cl.isFirstRun()) {
cl.getLogDialog().show();
}
## Changelog
### Version 0.1
* Initial release
## Acknowledgments
This library is based on:
* [android-change-log](http://code.google.com/p/android-change-log/) by Karsten Priegnitz
* [Inscription](https://github.com/MartinvanZ/Inscription/) by [Martin van Zuilekom](https://github.com/MartinvanZ/)
Other contributors:
* You? Pull requests welcome!
## License
Copyright (C) 2012 Christian Ketterer (cketti)
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.

View File

@ -0,0 +1,12 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="de.cketti.library.changelog"
android:versionCode="1"
android:versionName="0.1" >
<uses-sdk
android:minSdkVersion="7"
android:targetSdkVersion="17" />
<application/>
</manifest>

View File

@ -0,0 +1,15 @@
# This file is automatically generated by Android Tools.
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
#
# This file must be checked in Version Control Systems.
#
# To customize properties used by the Ant build system edit
# "ant.properties", and override values to adapt the script to your
# project structure.
#
# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
# Project target.
target=android-17
android.library=true

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<changelog />

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="changelog_full_title">Change Log</string>
<string name="changelog_title">What\'s New</string>
<string name="changelog_ok_button">OK</string>
<string name="changelog_show_full">More…</string>
<string name="changelog_version_format">Version <xliff:g id="version_name">%s</xliff:g></string>
</resources>

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<changelog />

View File

@ -0,0 +1,534 @@
/*
* Copyright (C) 2012 Christian Ketterer (cketti)
*
* Portions Copyright (C) 2012 Martin van Zuilekom (http://martin.cubeactive.com)
*
* 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.
*
*
* Based on android-change-log:
*
* Copyright (C) 2011, Karsten Priegnitz
*
* Permission to use, copy, modify, and distribute this piece of software
* for any purpose with or without fee is hereby granted, provided that
* the above copyright notice and this permission notice appear in the
* source code of all copies.
*
* It would be appreciated if you mention the author in your change log,
* contributors list or the like.
*
* http://code.google.com/p/android-change-log/
*/
package de.cketti.library.changelog;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
import android.preference.PreferenceManager;
import android.util.Log;
import android.util.SparseArray;
import android.webkit.WebView;
/**
* Display a dialog showing a full or partial (What's New) change log.
*/
public class ChangeLog {
/**
* Tag that is used when sending error/debug messages to the log.
*/
protected static final String LOG_TAG = "ckChangeLog";
/**
* This is the key used when storing the version code in SharedPreferences.
*/
protected static final String VERSION_KEY = "ckChangeLog_last_version_code";
/**
* Constant that used when no version code is available.
*/
protected static final int NO_VERSION = -1;
/**
* Default CSS styles used to format the change log.
*/
private static final String DEFAULT_CSS =
"h1 { margin-left: 0px; font-size: 1.2em;}" +
"li { margin-left: 0px;}" +
"ul { padding-left: 2em;}";
/**
* Context that is used to access the resources and to create the ChangeLog dialogs.
*/
protected final Context mContext;
/**
* Contains the CSS rules used to format the change log.
*/
protected final String mCss;
/**
* Last version code read from {@code SharedPreferences} or {@link #NO_VERSION}.
*/
private int mLastVersionCode;
/**
* Version code of the current installation.
*/
private int mCurrentVersionCode;
/**
* Version name of the current installation.
*/
private String mCurrentVersionName;
/**
* Contains constants for the root element of {@code changelog.xml}.
*/
protected interface ChangeLogTag {
static final String NAME = "changelog";
}
/**
* Contains constants for the release element of {@code changelog.xml}.
*/
protected interface ReleaseTag {
static final String NAME = "release";
static final String ATTRIBUTE_VERSION = "version";
static final String ATTRIBUTE_VERSION_CODE = "versioncode";
}
/**
* Contains constants for the change element of {@code changelog.xml}.
*/
protected interface ChangeTag {
static final String NAME = "change";
}
/**
* Create a {@code ChangeLog} instance using the default {@link SharedPreferences} file.
*
* @param context
* Context that is used to access the resources and to create the ChangeLog dialogs.
*/
public ChangeLog(Context context) {
this(context, PreferenceManager.getDefaultSharedPreferences(context), DEFAULT_CSS);
}
/**
* Create a {@code ChangeLog} instance using the default {@link SharedPreferences} file.
*
* @param context
* Context that is used to access the resources and to create the ChangeLog dialogs.
* @param css
* CSS styles that will be used to format the change log.
*/
public ChangeLog(Context context, String css) {
this(context, PreferenceManager.getDefaultSharedPreferences(context), css);
}
/**
* Create a {@code ChangeLog} instance using the supplied {@code SharedPreferences} instance.
*
* @param context
* Context that is used to access the resources and to create the ChangeLog dialogs.
* @param preferences
* {@code SharedPreferences} instance that is used to persist the last version code.
* @param css
* CSS styles used to format the change log (excluding {@code <style>} and
* {@code </style>}).
*
*/
public ChangeLog(Context context, SharedPreferences preferences, String css) {
mContext = context;
mCss = css;
// Get last version code
mLastVersionCode = preferences.getInt(VERSION_KEY, NO_VERSION);
// Get current version code and version name
try {
PackageInfo packageInfo = context.getPackageManager().getPackageInfo(
context.getPackageName(), 0);
mCurrentVersionCode = packageInfo.versionCode;
mCurrentVersionName = packageInfo.versionName;
} catch (NameNotFoundException e) {
mCurrentVersionCode = NO_VERSION;
Log.e(LOG_TAG, "Could not get version information from manifest!", e);
}
}
/**
* Get version code of last installation.
*
* @return The version code of the last installation of this app (as described in the former
* manifest). This will be the same as returned by {@link #getCurrentVersionCode()} the
* second time this version of the app is launched (more precisely: the second time
* {@code ChangeLog} is instantiated).
*
* @see AndroidManifest.xml#android:versionCode
*/
public int getLastVersionCode() {
return mLastVersionCode;
}
/**
* Get version code of current installation.
*
* @return The version code of this app as described in the manifest.
*
* @see AndroidManifest.xml#android:versionCode
*/
public int getCurrentVersionCode() {
return mCurrentVersionCode;
}
/**
* Get version name of current installation.
*
* @return The version name of this app as described in the manifest.
*
* @see AndroidManifest.xml#android:versionName
*/
public String getCurrentVersionName() {
return mCurrentVersionName;
}
/**
* Check if this is the first execution of this app version.
*
* @return {@code true} if this version of your app is started the first time.
*/
public boolean isFirstRun() {
return mLastVersionCode < mCurrentVersionCode;
}
/**
* Check if this is a new installation.
*
* @return {@code true} if your app including {@code ChangeLog} is started the first time ever.
* Also {@code true} if your app was uninstalled and installed again.
*/
public boolean isFirstRunEver() {
return mLastVersionCode == NO_VERSION;
}
/**
* Get the "What's New" dialog.
*
* @return An AlertDialog displaying the changes since the previous installed version of your
* app (What's New). But when this is the first run of your app including
* {@code ChangeLog} then the full log dialog is show.
*/
public AlertDialog getLogDialog() {
return getDialog(isFirstRunEver());
}
/**
* Get a dialog with the full change log.
*
* @return An AlertDialog with a full change log displayed.
*/
public AlertDialog getFullLogDialog() {
return getDialog(true);
}
/**
* Create a dialog containing (parts of the) change log.
*
* @param full
* If this is {@code true} the full change log is displayed. Otherwise only changes for
* versions newer than the last version are displayed.
*
* @return A dialog containing the (partial) change log.
*/
protected AlertDialog getDialog(boolean full) {
WebView wv = new WebView(mContext);
//wv.setBackgroundColor(0); // transparent
wv.loadDataWithBaseURL(null, getLog(full), "text/html", "UTF-8", null);
AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
builder.setTitle(
mContext.getResources().getString(
full ? R.string.changelog_full_title : R.string.changelog_title))
.setView(wv)
.setCancelable(false)
// OK button
.setPositiveButton(
mContext.getResources().getString(R.string.changelog_ok_button),
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// The user clicked "OK" so save the current version code as
// "last version code".
updateVersionInPreferences();
}
});
if (!full) {
// Show "More…" button if we're only displaying a partial change log.
builder.setNegativeButton(R.string.changelog_show_full,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
getFullLogDialog().show();
}
});
}
return builder.create();
}
/**
* Write current version code to the preferences.
*/
protected void updateVersionInPreferences() {
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext);
SharedPreferences.Editor editor = sp.edit();
editor.putInt(VERSION_KEY, mCurrentVersionCode);
// TODO: Update preferences from a background thread
editor.commit();
}
/**
* Get changes since last version as HTML string.
*
* @return HTML string containing the changes since the previous installed version of your app
* (What's New).
*/
public String getLog() {
return getLog(false);
}
/**
* Get full change log as HTML string.
*
* @return HTML string containing the full change log.
*/
public String getFullLog() {
return getLog(true);
}
/**
* Get (partial) change log as HTML string.
*
* @param full
* If this is {@code true} the full change log is returned. Otherwise only changes for
* versions newer than the last version are returned.
*
* @return The (partial) change log.
*/
private String getLog(boolean full) {
StringBuilder sb = new StringBuilder();
sb.append("<html><head><style type=\"text/css\">");
sb.append(mCss);
sb.append("</style></head><body>");
Resources resources = mContext.getResources();
// Read master change log from raw/changelog.xml
SparseArray<ReleaseItem> defaultChangelog;
try {
XmlPullParser xml = XmlPullParserFactory.newInstance().newPullParser();
InputStreamReader reader = new InputStreamReader(resources.openRawResource(R.raw.changelog));
xml.setInput(reader);
try {
defaultChangelog = readChangeLog(xml, full);
} finally {
try { reader.close(); } catch (Exception e) { /* do nothing */ }
}
} catch (XmlPullParserException e) {
Log.e(LOG_TAG, "Error reading raw/changelog.xml", e);
return null;
}
// Read localized change log from xml[-lang]/changelog.xml
XmlResourceParser resXml = mContext.getResources().getXml(R.xml.changelog);
SparseArray<ReleaseItem> changelog;
try {
changelog = readChangeLog(resXml, full);
} finally {
resXml.close();
}
String versionFormat = resources.getString(R.string.changelog_version_format);
// Get all version codes from the master change log...
List<Integer> versions = new ArrayList<Integer>(defaultChangelog.size());
for (int i = 0, len = defaultChangelog.size(); i < len; i++) {
int key = defaultChangelog.keyAt(i);
versions.add(key);
}
// ... and sort them (newest version first).
Collections.sort(versions, Collections.reverseOrder());
for (Integer version : versions) {
int key = version.intValue();
// Use release information from localized change log and fall back to the master file
// if necessary.
ReleaseItem release = changelog.get(key, defaultChangelog.get(key));
sb.append("<h1>");
sb.append(String.format(versionFormat, release.versionName));
sb.append("</h1><ul>");
for (String change : release.changes) {
sb.append("<li>");
sb.append(change);
sb.append("</li>");
}
sb.append("</ul>");
}
sb.append("</body></html>");
return sb.toString();
}
/**
* Read the change log from an XML file.
*
* @param xml
* The {@code XmlPullParser} instance used to read the change log.
* @param full
* If {@code true} the full change log is read. Otherwise only the changes since the
* last (saved) version are read.
*
* @return A {@code SparseArray} mapping the version codes to release information.
*/
protected SparseArray<ReleaseItem> readChangeLog(XmlPullParser xml, boolean full) {
SparseArray<ReleaseItem> result = new SparseArray<ReleaseItem>();
try {
int eventType = xml.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT) {
if (eventType == XmlPullParser.START_TAG && xml.getName().equals(ReleaseTag.NAME)) {
if (parseReleaseTag(xml, full, result)) {
// Stop reading more elements if this entry is not newer than the last
// version.
break;
}
}
eventType = xml.next();
}
} catch (XmlPullParserException e) {
Log.e(LOG_TAG, e.getMessage(), e);
} catch (IOException e) {
Log.e(LOG_TAG, e.getMessage(), e);
}
return result;
}
/**
* Parse the {@code release} tag of a change log XML file.
*
* @param xml
* The {@code XmlPullParser} instance used to read the change log.
* @param full
* If {@code true} the contents of the {@code release} tag are always added to
* {@code changelog}. Otherwise only if the item's {@code versioncode} attribute is
* higher than the last version code.
* @param changelog
* The {@code SparseArray} to add a new {@link ReleaseItem} instance to.
*
* @return {@code true} if the {@code release} element is describing changes of a version older
* or equal to the last version. In that case {@code changelog} won't be modified and
* {@link #readChangeLog(XmlPullParser, boolean)} will stop reading more elements from
* the change log file.
*
* @throws XmlPullParserException
* @throws IOException
*/
private boolean parseReleaseTag(XmlPullParser xml, boolean full,
SparseArray<ReleaseItem> changelog) throws XmlPullParserException, IOException {
String version = xml.getAttributeValue(null, ReleaseTag.ATTRIBUTE_VERSION);
int versionCode;
try {
String versionCodeStr = xml.getAttributeValue(null, ReleaseTag.ATTRIBUTE_VERSION_CODE);
versionCode = Integer.parseInt(versionCodeStr);
} catch (NumberFormatException e) {
versionCode = NO_VERSION;
}
if (!full && versionCode <= mLastVersionCode) {
return true;
}
int eventType = xml.getEventType();
List<String> changes = new ArrayList<String>();
while (eventType != XmlPullParser.END_TAG || xml.getName().equals(ChangeTag.NAME)) {
if (eventType == XmlPullParser.START_TAG && xml.getName().equals(ChangeTag.NAME)) {
eventType = xml.next();
changes.add(xml.getText());
}
eventType = xml.next();
}
ReleaseItem release = new ReleaseItem(versionCode, version, changes);
changelog.put(versionCode, release);
return false;
}
/**
* Container used to store information about a release/version.
*/
protected static class ReleaseItem {
/**
* Version code of the release.
*/
public final int versionCode;
/**
* Version name of the release.
*/
public final String versionName;
/**
* List of changes introduced with that release.
*/
public final List<String> changes;
ReleaseItem(int versionCode, String versionName, List<String> changes) {
this.versionCode = versionCode;
this.versionName = versionName;
this.changes = changes;
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -15,3 +15,4 @@ target=android-15
extensible.libs.classpath=compile-only-libs extensible.libs.classpath=compile-only-libs
android.library.reference.1=plugins/ActionBarSherlock/library android.library.reference.1=plugins/ActionBarSherlock/library
android.library.reference.2=plugins/Android-PullToRefresh/library android.library.reference.2=plugins/Android-PullToRefresh/library
android.library.reference.3=plugins/ckChangeLog/library

12
res/raw/changelog.xml Normal file
View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<changelog>
<release version="4.320" versioncode="17021" >
<change>New feature here</change>
</release>
<release version="4.319" versioncode="17020" >
<change>Added Jelly Bean-style notifications</change>
</release>
</changelog>

View File

@ -89,6 +89,8 @@ import com.fsck.k9.preferences.SettingsImporter.AccountDescriptionPair;
import com.fsck.k9.preferences.SettingsImporter.ImportContents; import com.fsck.k9.preferences.SettingsImporter.ImportContents;
import com.fsck.k9.preferences.SettingsImporter.ImportResults; import com.fsck.k9.preferences.SettingsImporter.ImportResults;
import de.cketti.library.changelog.ChangeLog;
public class Accounts extends K9ListActivity implements OnItemClickListener { public class Accounts extends K9ListActivity implements OnItemClickListener {
@ -414,6 +416,11 @@ public class Accounts extends K9ListActivity implements OnItemClickListener {
if (mNonConfigurationInstance != null) { if (mNonConfigurationInstance != null) {
mNonConfigurationInstance.restore(this); mNonConfigurationInstance.restore(this);
} }
ChangeLog cl = new ChangeLog(this);
if (cl.isFirstRun()) {
cl.getLogDialog().show();
}
} }
private void initializeActionBar() { private void initializeActionBar() {

View File

@ -71,6 +71,8 @@ import com.fsck.k9.search.SearchSpecification.Attribute;
import com.fsck.k9.search.SearchSpecification.Searchfield; import com.fsck.k9.search.SearchSpecification.Searchfield;
import com.fsck.k9.service.MailService; import com.fsck.k9.service.MailService;
import de.cketti.library.changelog.ChangeLog;
/** /**
* FolderList is the primary user interface for the program. This * FolderList is the primary user interface for the program. This
* Activity shows list of the Account's folders * Activity shows list of the Account's folders
@ -308,6 +310,11 @@ public class FolderList extends K9ListActivity implements OnNavigationListener {
onNewIntent(getIntent()); onNewIntent(getIntent());
context = this; context = this;
ChangeLog cl = new ChangeLog(this);
if (cl.isFirstRun()) {
cl.getLogDialog().show();
}
} }
private void initializeActionBar() { private void initializeActionBar() {

View File

@ -39,6 +39,8 @@ import com.fsck.k9.search.SearchSpecification.Attribute;
import com.fsck.k9.search.SearchSpecification.Searchfield; import com.fsck.k9.search.SearchSpecification.Searchfield;
import com.fsck.k9.search.SearchSpecification.SearchCondition; import com.fsck.k9.search.SearchSpecification.SearchCondition;
import de.cketti.library.changelog.ChangeLog;
/** /**
* MessageList is the primary user interface for the program. This Activity * MessageList is the primary user interface for the program. This Activity
@ -145,6 +147,11 @@ public class MessageList extends K9FragmentActivity implements MessageListFragme
ft.add(R.id.message_list_container, mMessageListFragment); ft.add(R.id.message_list_container, mMessageListFragment);
ft.commit(); ft.commit();
} }
ChangeLog cl = new ChangeLog(this);
if (cl.isFirstRun()) {
cl.getLogDialog().show();
}
} }
private void decodeExtras(Intent intent) { private void decodeExtras(Intent intent) {